带有Redux的React Native组件在每次向Redux存储添加新记录时重新呈现

dwthyt8l  于 2023-05-18  发布在  React
关注(0)|答案(1)|浏览(143)

我有一个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钩子引起的不必要的重新呈现?
谢谢你的帮助!

mefy6pfw

mefy6pfw1#

你的选择器结果似乎永远不会是浅相等的--它每次都是一个全新数组的对象。
您不能在useSelector调用站点级别上解决这个问题,但是您可以记住您的选择器。给予deriving data with selectors

相关问题