【问题标题】:React Redux accessing dynamically filtered state in mapStateToProps - rerendering woesReact Redux 访问 mapStateToProps 中的动态过滤状态 - 重新渲染问题
【发布时间】:2021-01-19 16:00:15
【问题描述】:

我有一个功能组件,它传递了关于从 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]

我尝试使用 reselect 和 rereselect 而不是上面的 getItemsFromState 函数, 但结果都是一样的。该树中的任何更改(从表面[6] 开始)都会触发 mapsStateToProps 和重新渲染。

一定有办法解决这个问题,但我想不通。我尝试使用areStatesEqual,但它只提供nextStateprevState,我需要ownProps 来计算相等性。我可能可以使用areStatePropsEqual,但这仅在不必要地重新计算mapStateToProps 之后才有效。

一定有办法!

【问题讨论】:

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


    【解决方案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

    【讨论】:

      猜你喜欢
      • 2018-12-12
      • 2020-07-15
      • 2021-02-09
      • 2022-10-07
      • 2018-12-31
      • 1970-01-01
      • 1970-01-01
      • 2018-12-02
      • 2020-10-26
      相关资源
      最近更新 更多