我试图通过限制内容未更改的组件的渲染调用次数来了解如何在React中管理复杂状态。
例如:
我已使用“ items”道具(即数组)简单地连接到redux存储容器组件。
const Component = ({ items }) => (
<>{items.map(item => <ItemComponent key={item.id} {...item} />}</>
);
const mapStateToProps = state => ({
items: $$data.select.items(state),
});
const ConnectedComponent = connect(mapStateToProps)(MyComponent);
每次复杂存储的任何部分发生更改时-即使项数据没有更新,即使项数据为空,项属性也会更改:oldProp:[] => newProp:[]。并导致重新渲染。 (我在React Dev Tools中找到了它,它突出显示了更新的组件)
我应该担心这种不必要的退货吗?最好的解决方法是什么? 我已经发现新的React.memo hoc可以停止重新渲染,但这是个好方法吗?
答案 0 :(得分:5)
在mapStateToProps
调用中使用connect()
意味着您希望在商店更改时通知您的组件-无论您感兴趣的小片段是否已更改,都会发生这种情况除此之外,react-redux
通过对mapStateToProps
返回的对象和先前的道具进行浅表比较来防止不必要的重新渲染。
以您的示例为例,每次newProp: []
这样的场景都会创建一个新数组,因此,由于数组是不同的实例,因此无法进行较浅的比较。
我应该担心这种不必要的放弃吗?
React注意不要不必要地重新渲染组件,因此,即使再次调用render
,只要对组件的props
并未实际更改,React也不会做任何其他操作工作。可以肯定地说,对于大多数应用程序而言,不必要的重新渲染并不是所有问题。
如果您认为它会影响您的应用程序,或者您只是想了解更多有关减少它的方法,那么关于性能的材料很多:
答案 1 :(得分:4)
减速器很可能有问题。否则,您可以使用reselect
库来定义用于记忆值的选择器,这样除非值真正更改,否则不会重新渲染。
答案 2 :(得分:3)
将您的组件与商店连接意味着“在更改道具时调用我的组件或组件的渲染方法”。默认比较是通过简单的相等性检查进行的,这在您的数据中可能为假。
因此,在您的应用程序中,即使没有必要,也很有可能创建了新的对象或数组。这是您遇到的第一个更大的问题。
即使您的组件需要重新渲染,它也会执行render方法,但是您的影子dom仍然是相同的,因此在大多数情况下,您无需进行任何昂贵的操作。
您可以执行以下步骤:
-不要创建不必要的新对象和数组引用。好吧,这是正确且更长的解决方案
-使用mapStateToProps实现自己的相等性检查。有很多优化选择器逻辑的方法,但这取决于应用程序的详细信息。最好在此处关注此帖子:https://medium.com/practo-engineering/avoiding-re-renders-in-react-and-optimising-mapstatetoprops-with-reselect-6e199fa7bc73
我应该担心这种不必要的放弃吗?
这实际上取决于您的应用程序的大小。您可能应该有一些基准测试,并检查一些反应性能工具。
答案 3 :(得分:1)
您可以使用组件生命周期方法shouldComponentUpdate
,该方法将通过nextState
和nextProps
传递。这样,您可以通过返回true
(更新)或false
(不更新)来决定组件是否需要更新。
文档:here。
答案 4 :(得分:0)
如果您使用的是react-redux
> = 6.0.0
,则React DevTools中有一个错误,会错误地显示突出显示的重新渲染。
带有“重点更新”的误报
https://github.com/facebook/react-devtools/issues/1290
这里发生的是包装的组件将被重新渲染,而不是您正在使用connect
的组件。