我有一个React Native组件,它使用Redux来管理状态。该组件有一个useSelector钩子,用于从Redux存储中选择记录。每次向存储添加新记录时,整个组件都会重新呈现(包括FlashList中的所有组件)。这会导致RecordCard组件不必要地重新呈现(每次添加记录时,都要重新呈现所有现有记录),从而导致性能下降。
下面是代码的简化版本:
组件
const RecordsScreen = () => {
const records: { [key: string]: SingleRecord[] } = useSelector(selectFilteredRecords, shallowEqual);
const keys = Object.keys(records);
const keyExtractor = useCallback((item: any, index: number) => index, []);
class RenderItem extends React.PureComponent {
render() {
const { dateString } = this.props;
const dateRecords = records[dateString];
return (
<Collapsible>
<FlashList
data={dateRecords}
keyExtractor={keyExtractor}
renderItem={({ item }) => (<RecordCard record={item} />)}
removeClippedSubviews={true}
estimatedItemSize={dateRecords.length === 0 ? 1 : dateRecords.length}
/>
</Collapsible>
);
}
}
function areEqual(prevProps: any, nextProps: any) {
return JSON.stringify(prevProps) === JSON.stringify(nextProps);
}
const Memoized = memo(RenderItem, areEqual);
return (
<View>
<FlashList
data={keys}
keyExtractor={keyExtractor}
renderItem={({ dateString }) => (<Memoized dateString={dateString} />)}
removeClippedSubviews={true}
estimatedItemSize={keys.length === 0 ? 1 : keys.length}
/>
</View>
);
};
export default RecordsScreen;
Redux代码
interface RecordsState {
records: { [key: string]: SingleRecord[] }; // where the key is a date in string format
recordsFilter: Filter;
}
const initialState: RecordsState = {
records: {},
recordsFilter: new Filter()
};
...
// using reselect
export const selectFilteredRecords = createSelector(
selectRecords,
selectRecordsFilter,
(records, filter) => {
return filterRecords(records, filter);
}
);
const filterRecords = (records: any, filter: any) => {
const filteredRecords: { [key: string]: SingleRecord[] } = {};
if (records !== null && records !== undefined) {
Object.entries(records).forEach(([dateKey, records]: any) => {
const filteredRecords = records.filter((record: any) => {
if (filter.fromDate && record.date! < new Date(filter.fromDate)) {
return false;
}
if (filter.toDate && record.date! > new Date(filter.toDate)) {
return false;
}
if (filter.account && record.account !== filter.account) {
return false;
}
if (filter.category && record.category !== filter.category) {
return false;
}
if (filter.subCategory && record.subCategory !== filter.subCategory) {
return false;
}
if (filter.currency && filter.currency !== record.currency) {
return false;
}
return true;
});
if (filteredRecords.length > 0) {
filteredRecords[dateKey] = filteredRecords;
}
});
}
return filteredRecords;
}
我在useSelector钩子中使用了shallowEqual相等函数来防止不必要的重新呈现,但它没有帮助。
我尝试过使用React.memo高阶组件来记忆RecordCard和Collapsible组件,但它没有解决问题。
我也尝试过使用useCallback钩子来记忆keyExtractor函数,但它并没有解决这个问题。
我可以做些什么来防止由useSelector钩子引起的不必要的重新呈现?
谢谢你的帮助!
1条答案
按热度按时间mefy6pfw1#
你的选择器结果似乎永远不会是浅相等的--它每次都是一个全新数组的对象。
您不能在
useSelector
调用站点级别上解决这个问题,但是您可以记住您的选择器。给予deriving data with selectors。