【问题标题】:React component remounts when state object is reordered当状态对象重新排序时,React 组件会重新挂载
【发布时间】:2019-07-03 16:46:09
【问题描述】:

我有一个 react-redux 应用程序,并且正在使用 react-transition-group 在状态更改中子组件位置更改时进行转换。但是,如果我的 redux 状态对象的顺序发生变化,组件将卸载然后重新安装,而不是更新。这可以防止组件平滑过渡到其新位置。有没有办法在不引入新状态的情况下解决这个问题?

我的父组件如下所示:

class ParentComponent extends Component {
...
render() {
return (
   <div>
      <div>
         <CSSTransitionGroup>
            <ChildComponents childComponentsToRender= 
               {this.props.someChildComponents}/>
         <CSSTransitionGroup/>
      </div>
   </div>
)}}

ChildComponents 看起来像这样:

export default function ChildComponents(props) {
   const childrenToReturn = _.map(props.childComponentsToRender, 
      (childComponent) => 
      <ChildComponent 
         key={childComponent.uniqueId} 
         position={childComponent.position} .../>
   return (
      <Fragment>
         {childrenToReturn}
      </Fragment>
   )
}

一个单独的 ChildComponent 看起来像这样:

export default function ChildComponent(props) {
   return (
      <div style={{transform: `translate(${props.position.x}px, 
         ${props.position.y}px)`}}>
      </div>
   )
}

我渲染组件的 redux 状态如下:

{
   ...,
   someChildComponents: {
      childComponent1: {
         id: someUniqueId,
         position: {x: int, y: int}
      },
      childComponent2: {
         id: someUniqueId,
         position: {x: int, y: int}
      },
      ...
   },
   ...
}

如果调度了一个动作并且状态会发生变化,就会出现问题,例如:

{
   someChildComponents: {
      childComponent1: {
         id: someUniqueId,
         position: {x: 100, y: 100}
      },
      childComponent2: {
         id: someUniqueId,
         position: {x: 200, y: 200}
      }
   }
}

收件人:

{
   someChildComponents: {
      childComponent2: {
         id: someUniqueId,
         position: {x: 300, y: 300}
      },
      childComponent1: {
         id: someUniqueId,
         position: {x: 150, y: 150}
      }
   }
}

【问题讨论】:

  • 对象不是 JavaScript 中的有序数据结构;您通过 name 而不是 position 访问他们的内容。
  • 位置,我的意思是一个元素被翻译的 x,y 对。

标签: reactjs redux react-redux


【解决方案1】:

如果你需要关联元素的特定位置,你最好需要数组,而不是对象。但我不建议将someChildComponents 转换为数组。在大多数情况下,存储不同数据时,对象优先于数组。

您可以根据您的someChildComponents 对象动态创建数组,例如使用selectors。您唯一需要的是 someChildComponents 对象中的一些唯一标识符,可用于对数组进行排序。

这是示例代码

const getChildrenComponents = state => state.someChildComponents;

export function makeArrayFromChildrenComponents() {
    return createSelector(
        [getChildrenComponents],
        (ChildrenComponents) => (
            Object.keys(ChildrenComponents).map(key => ChildrenComponents[key])
                .sort((e1, e2) => {
                    if (e1.id === e2.id) return 0;
                    return e1.id < e2.id ? -1 : 1;
                });
        )
    )
}

然后像这样使用它为ParentComponent提供稳定的子组件数组

const makeMapStateToProps = () => {
    const getChildrenComponentsArray = makeArrayFromChildrenComponents();
    const mapStateToProps = (state) => ({
        ChildrenComponents: getChildrenComponentsArray(state)
        // ... other mapped props
    });
    return mapStateToProps;
}

选择器会在状态改变时更新ChildrenComponents。但数组本身将保持相同的元素顺序。

您还可以查看 React 使用的 diffing algorithm 来决定是构建新树还是保留现有树。

【讨论】:

    猜你喜欢
    • 2022-01-24
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多