React useSelector hook 是传播对象更好还是只指定需要的字段

Com*_*ode 2 reactjs react-redux react-hooks

如果我有一个巨大的对象,比如(40+ 个字段),并且我在一个组件中调用 useSelector 但只需要此类对象的 3 个字段,那么只调用 3 个这样的字段是否会更好地提高性能:

const user = useSelector((state) => ({
    id: state.userReducer.id,
    name: state.userReducer.name,
    lastName: state.userReducer.lastName
  }));
Run Code Online (Sandbox Code Playgroud)

在这种情况下还可以,因为我们只需要 3 个字段,但是如果我们需要 10 个以上的字段,事情就会变得非常冗长。在这种情况下,展开运算符为我节省了大量代码,但这是一种不好的做法吗?由于代码、性能或其他一些原因的混淆?

const user = useSelector((state) => ({ ...state.userReducer }));
Run Code Online (Sandbox Code Playgroud)

tri*_*ixn 5

出于性能原因,您应该这样做:

const user = useSelector(state => state.userReducer);
Run Code Online (Sandbox Code Playgroud)

每当一个动作被调度时,你的选择器就会运行。如果它返回一些不同的东西,那么在最后一次运行时它会强制组件重新渲染。通过传播到一个新对象,它总是会返回一个新对象。因此,您的组件将在每个被调度的操作上重新渲染。

来自react-redux 文档

useSelector() 还将订阅 Redux 存储,并在调度操作时运行您的选择器。

[...]

  • 当一个动作被分派时,useSelector()会对之前的选择器结果值和当前的结果值做一个引用比较。如果它们不同,组件将被迫重新渲染

  • [...]

  • useSelector()===默认情况下使用严格的引用相等检查,而不是浅相等

我也觉得关键userReducer有点尴尬。它只是用户的user非减速器。reducer 是一个纯函数,它将动作转换为变化而不是数据对象。

编辑

正如@Adam 在评论中指出的那样,如果您想进一步减少重新渲染的数量,您可以使用记忆选择器来仅选择您感兴趣的状态。创建此类选择器的一个好库是reselect

// example

import { createSelector } from 'reselect'; 

const basicUserDataSelector = createSelector(
    ({user}) => user.id,
    ({user}) => user.name,
    ({user}) => user.lastName,
    (id, name, lastName) => ({id, name, lastName})
);

// usage

const user = useSelector(basicUserDataSelector);
Run Code Online (Sandbox Code Playgroud)

在您的情况下,仅选择所需状态的最简单方法是告诉useSelector进行浅等比较而不是参考相等比较。useSelector接受一个比较器函数作为第二个参数:

import { shallowEqual, useSelector } from 'react-redux'

const user = useSelector(
    ({user}) => ({
        id: user.id
        name: user.name
        lastName: user.lastName
    }),
    shallowEqual
);
Run Code Online (Sandbox Code Playgroud)

最佳做法是仅从存储中获取所需的尽可能少的数据以限制重新渲染的数量。选择更多实际需要的数据的额外成本取决于组件和所选数据的更改频率。