Redux选择器会导致不必要的组件渲染吗?

时间:2018-01-29 18:18:24

标签: redux selector

从我对Dan Abramov的egghead视频&javascript-redux-colocating-selectors-with-redurs'以及他的一些推文,使用选择器将状态映射到prop并从Component中删除此逻辑并将其放入Reducer(管理状态的位置)是一个好习惯。

虽然这很有意义,但每次将新状态添加到存储时,它也会导致我的组件呈现,即使只更改了状态对象的非相关属性。有没有办法在不使用重选器的情况下克服这个问题,对于更简单的情况可能有点矫枉过正?

2 个答案:

答案 0 :(得分:2)

如您所知,每次更新商店时都会调用mapStateToProps

组件是否会重新渲染取决于mapStateToProps返回的内容。 (实际上,它取决于mapStateToProps mapDispatchToProps返回的组合道具对象。)

React Redux(提供connect函数的库)对返回的对象和 last 返回的对象进行浅等式检查。如果相等性检查成功(即,确定先前返回的对象等于下一个返回的对象),则该组件将不会重新呈现。如果检查失败,则组件将重新呈现。

例如,假设您始终从mapStateToProps返回以下对象:

{
  items: [],
}

此对象永远不会等于它自己([] === []返回false,因为它们是不同的数组)。因此,相等性检查将失败,组件将重新呈现。

但是,React Redux执行更复杂的相等检查(可以找到shallowEqual函数的实现here)。

例如,即使{ a: 'b' } === { a: 'b'}返回false(它们是不同的对象),shallowEqual 也会将它们视为相等。这是因为shallowEqual会将返回对象的每个键与先前返回的对象的每个键进行比较,但只有一个级别。更多细节可以在我上面链接的实现中找到。

总结,如果您不希望重新渲染组件,则需要确保相等检查成功。

你可以:

  • 使用reducer
  • 将返回的对象保存到状态
  • 使用Reselect
  • 缓存结果
  • 手动在组件中实施shouldComponentUpdate

这些建议直接来自Redux的常见问题解答页面:https://redux.js.org/docs/faq/ReactRedux.html#react-rendering-too-often

您还可以确保mapStateToProps函数返回被shallowEqual视为相等的对象(例如,没有数组且只有一个深度的对象)。

为简单起见,我会选择重新选择。

答案 1 :(得分:2)

简短的回答是:不,不是。

但是,使用选择器时,有一个常见错误会导致不必要的组件渲染。您应该始终确保定义一次选择器。那是什么意思?

使用 connect 方法时,可以将 mapStateToProps 方法作为参数传递。此方法返回的对象将作为props传递给组件,如果您在此对象内定义选择器,则每次组件收到prop时都会重新定义选择器。这是一个示例:

这样定义选择器可能会导致组件不必要地呈现。这是因为每次将prop传递到组件时,基本上都是在重新定义 getSettings 方法。

@connect(state => ({
  getSettings: ()=>'sample output',
}))
class Sample extends React.Component {}

正确的方法是这样定义您的选择器,以便仅创建一次,并且引用将通过您的 mapStateToProps 参数传递。

const getSettings = () =>'sample output';
@connect(state => ({
  getSettings,
}))
class Sample extends React.Component {}