Performance issues with tree structure and shouldComponentUpdate in React / Redux

I am new to React, Redux and ImmutableJS and have encountered some performance issues.

I have a large tree-like data structure that I now store as a flat list in this structure:

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: [] }) }); 

Structuring it as a flat list simplifies updating nodes, I find that the interaction becomes sluggish as the tree grows. Interaction includes the ability to select one or more nodes, switch the visibility of their child nodes, update text, etc. It seems that the key reason for the sluggish interface is that the entire tree is redrawn for each interaction.

I want to use shouldComponentUpdate so that when updating node 3, nodes 2 and 4 are not updated. It would be easy if the data was saved as a tree (I could just check if this.props !== nextProps ), but since the data is stored in a flat list, the verification will be much more complicated.

How do I store data and use shouldComponentUpdate (or other methods) to support a smooth interface with hundreds or thousands of tree nodes?

Edit

I connected the storage at the top level, and then I have to transfer the entire storage to subcomponents.

My structure:

 <NodeTree> <NodeBranch> <Node>{{text}}</Node> <NodeTree>...</NodeTree> </NodeBranch> <NodeBranch> <Node>{{text}}</Node> <NodeTree>...</NodeTree> </NodeBranch> ... </NodeTree> 

<Node> can do a simple check with shouldComponentUpdate to see if the title has changed, but I don't have a similar solution to use in <NodeTree> or <NodeBranch> , given the recursive nature of the tree.

It seems like the best solution (thanks to @Dan Abramov) would be to connect each <NodeBranch> , but just a top-level connection. I will spend it tonight.

+13
reactjs redux
Jan 24 '16 at 21:48
source share
2 answers

I just added a new example showing just that.
You can run it as follows:

 git clone https://github.com/rackt/redux.git cd redux/examples/tree-view npm install npm start open http://localhost:3000/ 
+19
Jan 25 '16 at 4:58
source share

Dan Abramov’s decision in 99% of cases usually ends.

But the computation time required for each increment is proportional to O (n) the number of nodes in the tree, since each connected HOC node needs to execute a bit of code (e.g. identity matching ...). However, this code runs pretty fast.

If you test Dan Abramov’s solution, with 10k nodes on my laptop, I begin to see some delay when trying to increase the counter (for example, a delay of 100 ms). This is probably much worse on cheap mobile devices.

You could argue that you should not try to display 10,000 elements in the DOM right away, and I totally agree with that, but if you really want to display a lot of elements and connect them, it's not that simple.

If you want to turn this O (n) into O (1) , you can implement your own connect system, where the HOC (higher order component) subscription is activated only when the base counter is updated instead of all HOC subscribers.

I told how to do this in this.

I created an issue for reaction-reduction so that connect became more flexible and made it easy to configure the store subscription through options. The idea is that you should be able to reuse the connect code and effectively subscribe to state slicing changes instead of global state changes (i.e. 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) 

It is still your own responsibility to create a store enhancer using the subscribeNode method.

+6
Jan 25 '16 at 11:11
source share



All Articles