将整个对象传递给 redux 重新选择选择器,但仅当对象的一个​​属性发生更改时才更改它

问题描述

开始使用 Reselect,但有一件事我似乎找不到答案。

假设我有一个助手 fn (getVehicleList) 进行一些繁重的计算,所以我不希望它重新运行太多。我使用状态选择器来获取我需要的属性,例如:

const getVehicles = (state) => state.vehicles.vehicles;
const getVehicle = (state) => state.vehicles.vehicle;
const getUserId = (state) => state.auth.user.id;

然后我实现了createSelector

const getVehicles = createSelector(
  [getVehicles,getVehicle,getUserId],(vehicles,vehicle,id) => getVehicleList(
    vehicles,id,),);

现在,vehicle 返回一个具有多个字段的对象。如果这些字段中的任何一个发生变化,对象就会发生变化,因此所有内容都会重新计算。有没有办法停止这种重新计算,直到 id 并且只有车辆的 id 发生变化?

我尝试为 id 做一个状态选择器,比如

const getVehicle = (state) => state.vehicles.vehicle.id;

但这对我不起作用,因为我需要助手 fn 中的整个车辆对象,而不仅仅是 ID。

预先感谢您的帮助!

解决方法

您可以尝试以下操作:

const getVehicles = (state) => state.vehicles.vehicles;
const getVehicle = (state) => state.vehicles.vehicle;
const getUserId = (state) => state.auth.user.id;
const selectVhicleId = createSelector(
  [getVehicle],({ id }) => id //return only the id
);
const selectVehicles = createSelector(
  [getVehicles,selectVhicleId,getUserId],(vehicles,vehicleId,id) =>
    getVehicleList(vehicles,{ id: vehicleId },id)
);

Here 是关于我如何在 React 中使用 reselect 的一些信息。

这里有一个例子,当 Vehicle.id 改变(或任何其他依赖项)时重新计算车辆。它不会重新计算车辆的其他值是否发生变化,因此使用的车辆 getVehicleList 获取传递给它的陈旧车辆,该车辆仅在 Vehicle.id 更改时刷新:

const getVehicles = (state) => state.vehicles.vehicles;
const getVehicle = (state) => state.vehicles.vehicle;
const getUserId = (state) => state.auth.user.id;
const createSelectVehicles = (vehicle) =>
  createSelector([getVehicles,vehicle,id)
  );

const Component = () => {
  //only re calculate vehicle if vehicle.id changes
  const vehicle = useSelector(
    getVehicle,(a,b) => a?.id === b?.id
  );
  //only create the selector when vehicle changes
  //  vehicle only changes when vehicle.id changes
  const selectVehicles = React.useMemo(
    () => createSelectVehicles(vehicle),[vehicle]
  );
  //vehicles is re calculated when vehicle.id changes
  //  or when state.vehicles.vehicles changes or
  //  when state.auth.user.id changes
  const vehicles = useSelector(selectVehicles);
};