使用 useSelector 钩子关闭重新渲染太多

Too many re-renders with useSelector hook closure

考虑到这个状态,我需要select从中获取一些数据:

const initialState: PlacesStateT = {
    activeTicket: null,
    routes: {
        departure: {
            carriageType: 'idle',
            extras: {
                wifi_price: 0,
                linens_price: 0,
            },
        },
        arrival: {
            carriageType: 'idle',
            extras: {
                wifi_price: 0,
                linens_price: 0,
            },
        },
    },
};

所以,我想到了两种方法:

第一个:

const useCoaches = (dir: string) => {
    const name = mapDirToRoot(dir);
    const carType = useAppSelector((state) => state.places.routes[name].carriageType);

    const infoT = useAppSelector((state) => {
        return state.places.activeTicket.trainsInfo.find((info) => {
            return info.routeName === name;
        });
    });

    const coaches = infoT.trainInfo.seatsTrainInfo.filter((coach) => {
        return coach.coach.class_type === carType;
    });

    return coaches;
};

第二个:

const handlerActiveCoaches = (name: string) => (state: RootState) => {
    const { carriageType } = state.places.routes[name];
    const { activeTicket } = state.places;

    const trainInfo = activeTicket.trainsInfo.find((info) => {
        return info.routeName === name;
    });

    return trainInfo.trainInfo.seatsTrainInfo.filter((coach) => {
        return coach.coach.class_type === carriageType;
    });
};

const useActiveInfo = (dir: string) => {
    const routeName = mapDirToRoot(dir);
    const selectActiveCoaches = handlerActiveCoaches(routeName);
    const coaches = useAppSelector(selectActiveCoaches);

    return coaches;
};

最终,如果第一个工作正常,那么第二个在组件中给出了很多无用的重新渲染。我怀疑 selectActiveCoaches 关闭有问题,也许 React 认为这个 selector 在每次重新渲染时都不同,但也许我错了。你能解释一下它是如何工作的吗?

selectActiveCoachesreturn seatsTrainInfo.filter() 结束。这 always returns 一个新的数组引用,并且 useSelector 将强制您的组件 re-render 每当您的选择器 returns 一个不同的引用上次。因此,在 每个 调度操作之后,您强制组件 re-render:

https://react-redux.js.org/api/hooks#equality-comparisons-and-updates

这里的一个选项是使用 Reselect 将其重写为记忆选择器:

https://redux.js.org/usage/deriving-data-selectors