树结构的性能问题和React/Redux中的shouldComponentUpdate

Pad*_*ann 14 reactjs immutable.js redux

我对React,Redux和ImmutableJS很新,并且遇到了一些性能问题.

我有一个大型的数据树结构,我目前正在这个结构中存储为一个平面列表:

new Map({
  1: new Node({
    id: 1,
    text: 'Root',
    children: [2,3]
  }),
  2: new Node({
    id: 2,
    text: 'Child 1',
    children: [4]
  }),
  3: new Node({
    id: 3,
    text: 'Child 2',
    children: []
  }),
  4: new Node({
    id: 4,
    text: 'Child of child 1',
    children: []
  })
});
Run Code Online (Sandbox Code Playgroud)

虽然将其构建为平面列表使得更新节点变得容易,但我发现随着树的增长,交互变得缓慢.交互包括能够选择一个或多个节点,切换其子节点的可见性,更新文本等.看起来缓慢的UI的一个关键原因是每次交互都重绘整个树.

我想使用shouldComponentUpdate如果我更新节点3,节点2和4不更新.如果将数据存储为树(我可以简单地检查是否this.props !== nextProps),这将很容易,但是当数据存储在平面列表中时,检查将更加复杂.

我应该如何存储数据并使用shouldComponentUpdate(或其他方法)来支持具有数百或数千个树节点的平滑UI?

编辑

我一直在顶层连接商店,然后必须将整个商店传递给子组件.

我的结构是:

<NodeTree> 
  <NodeBranch>
    <Node>{{text}}</Node>
    <NodeTree>...</NodeTree>
  </NodeBranch>
  <NodeBranch>
    <Node>{{text}}</Node>
    <NodeTree>...</NodeTree>
  </NodeBranch>
  ...
</NodeTree>
Run Code Online (Sandbox Code Playgroud)

<Node>可以做一个简单的检查以shouldComponentUpdate查看是否标题已经改变,但我没有类似的解决方案对使用<NodeTree><NodeBranch>树给出的递归性质.

看起来最好的解决方案(感谢@Dan Abramov)将连接每个<NodeBranch>,而不仅仅是在顶层连接.我今天晚上要测试一下.

Dan*_*mov 19

刚刚添加了一个新示例.
你可以像这样运行它:

git clone https://github.com/rackt/redux.git

cd redux/examples/tree-view
npm install
npm start

open http://localhost:3000/
Run Code Online (Sandbox Code Playgroud)

  • 链接是404ing.[这是现在的链接吗?](https://github.com/reactjs/redux/tree/master/examples/tree-view) (2认同)

Seb*_*ber 6

Dan Abramov解决方案在99%的常见病例中都很好.

但是每个增量所需的计算时间与树中节点的数量成比例O(n),因为每个连接节点HOC必须执行一点代码(如身份比较......).但是,这段代码的执行速度非常快.

如果您测试Dan Abramov解决方案,我的笔记本电脑上有10k节点,我会在尝试递增计数器时看到一些延迟(如100ms延迟).在便宜的移动设备上可能更糟糕.

有人可能会争辩说你不应该尝试在DOM中同时渲染10k项目,我完全同意这一点,但如果你真的想展示很多项目并连接它们就不那么简单了.

如果要将此O(n)转换O(1),则可以实现自己的connect系统,其中仅在更新基础计数器时触发HOC(高阶组件)订阅,而不是所有HOC的订阅.

我已经介绍了如何在这个答案中这样做.

我在react-redux上创建了一个问题,以便connect更灵活,并允许通过选项轻松自定义商店的订阅.我们的想法是,您应该能够重用connect代码并有效地订阅状态切片更改而不是全局状态更改(即store.subscribe()).

const mapStateToProps = (state,props) => {node: selectNodeById(state,props.nodeId)}

const connectOptions = {
   doSubscribe: (store,props) => store.subscribeNode(props.nodeId)
}

connect(mapStateToProps, undefined,connectOptions)(ComponentToConnect)
Run Code Online (Sandbox Code Playgroud)

使用subscribeNode方法创建商店增强器仍然是您自己的责任.