React Redux在mapStateToProps中访问动态过滤的状态-重新呈现问题

时间:2020-10-04 17:11:42

标签: redux react-redux react-component reselect mapstatetoprops

我有一个功能组件,该组件传递了有关从redux存储中提取内容的指令。 使用mapStateToProps=(state, ownProps),我可以很高兴地从状态(存储)中拉出所需的项目-但是,以牺牲整个状态树中的任何更改为代价,这会触发重新运行mapStateToProps和大量的重新渲染。

让我打开包装。

这是商店一部分的快照:

{
  settings: {...stuff...},
  projects: [...stuff...],
  definitions: [...stuff...],
  themes: [...stuff...],
  surfaces: {
    '6': {                                   <--- VARIABLE PASSED TO COMPONENT
      surface: {
        STRIP: [..stuff..],
        GLOBAL: {                            <--- CATEGORY PASSED TO COMPONENT
          DISPLAY: {...stuff...},
          ASSIGNMENT: {                      <--- LIST OF REQUIRED OBJECTS HAS 
            A_TRACK: {                       SUBCATEGORY AND TARGET (A_TRACK etc...)
              value: 0,
              type: 'switch',
              label: 'TRACK'                 
            },
            A_SEND: {                        <--- ANOTHER OBJECT I NEED TO GET
              value: 0,
              type: 'switch',
              label: 'SEND'
            },
            A_PAN: {
              value: 0,
              type: 'switch',
              label: 'PAN'
            },
          },
        FADER_BANKS: {...stuff...},  
        STATUS: {...stuff...},
        LOTS_MORE_STUFF

我的父组件将必需的指令传递给孩子。

<RefMixerGroup 
    portId = {this.props.portId}
    items={[
          {parent: 'GLOBAL', group: "ASSIGNMENT", target: "A_TRACK"},
          {parent: 'GLOBAL', group: "ASSIGNMENT", target: "A_SEND"},
           ]
          }
/>

mapStateToProps非常简单:

const mapStateToPropy = (state, ownProps) => {
    return {
        groupItems: getItemsFromState(state.surfaces[ownProps.portId].surface, ownProps.items)
    }
}

并通过一个简单的功能完成工作:

const getItemsFromState = (subState, items)=>{
    let groupItems=[]
    for (let i = 0; i < items.length; i++) {
        const item = items[i];
        const base = subState[item.parent];
        
        let groupItem = base[item.group][item.target]
        groupItems.push({...groupItem, target: item.target})
    }
    return groupItems
} 

但是因为我正在创建匹配项数组,所以我认为redux认为我应该订阅树中的每个项目……在这种情况下,当我只希望对找到的元素进行更改时,

surfaces[6].surface[GLOBAL][ASSIGNMENT][A_TRACK]
surfaces[6].surface[GLOBAL][ASSIGNMENT][A_SEND]

我尝试使用重新选择和重新选择而不是上面的getItemsFromState函数, 但所有结果相同。从表面[6]开始,该树中的任何更改都会触发mapsStateToProps并重新渲染。

必须有解决办法,但我无法弄清楚。我尝试使用areStatesEqual,但它仅提供nextStateprevState,并且我需要ownProps来计算相等性。我可能可以使用areStatePropsEqual,但这仅在不必要地重新计算mapStateToProps之后起作用。

一定有办法!

1 个答案:

答案 0 :(得分:1)

getItemsFromState 每次运行时都会创建一个新的groupItems数组引用。每次 分派动作后都会调用它。从connect re-renders any time any of the fields returned by mapState have changed to a new reference开始,您的代码将迫使React-Redux每次都重新渲染。

这就是为什么you should use memoized selectors to only return new derived data references if the input references have changed(通常使用Reselect的createSelector)的原因。如果您对Reselect的使用在这里没有帮助,则可能是您的选择器设置不正确,但是我需要查看具体示例以在此处提供建议。

这也是components should subscribe to the smallest amount of data that they actually need的原因。

如果您使用的是功能组件,建议您也使用useSelector而不是connect