2017-08-04 31 views
2

该redux文档指出,当使用redux与反应时,使用react-redux包中的connect。这应该没有必要shouldComponentUpdate - http://redux.js.org/docs/basics/UsageWithReact.html#implementing-container-components避免重新渲染不可能 - 但文档说应该不需要shouldComponentUpdate

终极版库的connect()函数,它提供了许多有用的优化,以防止不必要的重新渲染。 (这样做的一个结果是,你不应该担心自己实施shouldComponentUpdate的表现作出反应的建议。)

但是我的组件unnecesarily更新,因为我每天都尽管内容时returing一个新的数组的数组是一样的。这里是我的代码:

const AssetManagerSmart = connect(
    function(state) { 
     const { assets } = state; 
     return { 
      assetIds: assets.map(asset => asset.id) 
     } 
    } 
) 

看到这个assetIds,它是一个地图从Redux的状态数组。这导致我的组件重新渲染。为了简化上面的代码,我们可以想像assetIds被分配到一个新的浅等于阵列每次,像这样:

const AssetManagerSmart = connect(
    function(state) { 
     const { assets } = state; 
     return { 
      assetIds: ['hi'] 
     } 
    } 
) 

怎么会在文档说我不应该需要shouldComponentUpdate当我遇到上面?上面我看到每个人都在做,即使在官方的redux文档中的“用法与反应”部分。

回答

1

当连接是在默认模式pure它执行several checks旨在避免调用mapStateToProps,和如果它被调用时,防止被包装的成分的重新呈现如果没有什么改变。

要检查它是否应该运行mapStateToProps(和mergeProps)连接,使2个相等检查:

  • areStatesEqual - 检查整个国家使用全等改变。每当商店发生变化,这将返回false。但是,您可以覆盖它,以检查商店的某个部分是否发生了变化。在你的情况,你可能要检查是否assets发生了变化:

    (next, prev) => prev.assets === next.assets 
    
  • areOwnPropsEqual - 让一个浅平等检查是否提供给从连接返回的组件的道具已经改变。既然你不使用道具,你可以在理论上覆盖这个总是返回true,但是这会阻止完全改变道具的变化。

如果mapStateToProps调用2个执行检查,看它是否应该重新描绘被包装的成分:

  • areStatePropsEqual - 的mapStateToProps当前和先前结果之间浅平等。这将检查prev { assetIds: [] }是否等于{ assetIds: [] },并且由于assetsIds阵列发生更改将返回false

  • areMergedPropsEqual - 合并ownPropsmapStateToPropsmapDispatchToProps - 的mergeProps当前和以前的结果之间的浅平等。

所以,如果你的状态发生变化或你的道具的变化,mapStateToProps将被调用,并且assetIds将重新计算。您可以覆盖areStatesEqualareOwnPropsEqual,仅将应调用mapStateToProps的特定更改列入白名单。

mapStateToProps的结果将与之前的结果进行比较。您可以覆盖支票以实际查看assetIds中的物品是否发生了变化,但这可能很昂贵,并且您还需要在areMergedPropsEqual中使用相同的物品。更简单的选择是使用memoized选择器。

Memoized选择器

选择器可以采取一块存储的,并计算得到的数据。只要状态的相关部分没有改变,memoized选择器就会返回相同的结果(不执行计算)。由于结果是相同的数组(不是具有类似值的新数组),因此将通过areStatePropsEqualareMergedPropsEqual检查(除非其他更改)。

Reselect是一个库,可以帮助您创建memoized选择器。

这是如何创建的资产的IDS(未测试)一memoized选择:

import { createSelector } from 'reselect' 

const getAssets = ({ assets }) => assets; /** simple not memoized selector **/ 

const getAssetIds = createSelector(/** memoized selector **/ 
    getAssets, 
    (assets) => assets.map(asset => asset.id) 
); 
+0

谢谢@OriDrori,但我不明白为什么了Redux文档是说没有必要forComponentUpdate。使用记忆会增加空间复杂性。一个简单的浅比较会做的伎俩不是?此外,为什么要记忆'getAssets',因为redux存储中的'assets'字段只会在某些更改(如果reducers正确完成)时才会更改,所以这是一个简单的引用检查,“connect”连这个都不简单参考检查? – Blagoh

+0

在这里的'options'部分 - https://github.com/reactjs/react-redux/blob/master/docs/api.md#arguments - 它解释了如果'pure'是'true',它确实比较浅和参考平等,所以记忆'getAssets'不是正确的? – Blagoh

+1

我已经更新了答案。看看它是否给你你需要的信息。 'getAssets'不被记忆(它只是返回一个对状态的引用)。 –

相关问题