我正在研究一个 React 组件,它包装了 react-graph-vis 的Graph
组件。我的组件应该呈现某个图形,并提供一个按钮来向图形中添加节点。
我所做的简化版本是以下组件,它呈现一个(单节点)图形和一个按钮。单击该按钮应该向图形添加第二个节点。
class GraphWrapper extends React.Component {
constructor(props) {
var graph = {nodes: [{id: 1, label: '1'}], edges: []};
this.state = {
options: {},
graph: graph
};
}
addNode() {
var graph = this.state.graph;
graph.nodes.push({id: 2, label: '2'});
this.setState({});
}
render() {
return <div>
<Graph graph={this.state.graph}, options={this.state.options}/>
<button onClick={this.addNode.bind(this)}>Add Node</button>
</div>;
}
}
初始图形正在正确呈现。此外,单击该按钮会按预期更改状态。但是,图形可视化效果不会更改,第二个节点不会显示,并且尽管状态发生了变化,但似乎没有重新呈现<Graph/>
组件。
我错过了什么?
您应该始终将 React 状态视为不可变状态。在您的情况下,您正在改变状态,这意味着即使数组内容已更改,引用this.state.graph
和this.state.graph.nodes
也是相同的。
更好的addNode
版本:
addNode() {
var nodesCopy = this.state.graph.nodes.slice(); // this will create a copy with the same items
nodesCopy.push({id: 2, label: '2'});
this.setState({ graph: {nodes: nodesCopy, edges: []};);
}
请注意,由于您更改了nodes
引用,就像现在它指向一个新数组一样,您被迫级联它,更改每个引用,直到状态的根。
编辑
在这个答案的先前版本中,我暗示如果状态"引用"没有改变,React 就不会重新渲染。这是不正确的。setState
将始终导致重新渲染。但是,如果单个组件收到的道具没有更改,则可能会选择不更新。
关于你@snakile的评论,你所描述的最可能的原因是Graph
组件实现了 shouldComponentUpdate(nextProps, nextState),如果 prop 的引用graph
没有改变,那么组件就不会更新。这可以解释为什么你的按钮更新而Graph
没有。