React中使用Cytoscape.js如何获取动态添加元素后的图全量状态
问题原因
你调用cy.json()仅拿到初始状态的核心原因是使用了CytoscapeComponent的受控属性elements:每次组件触发重渲染时,组件都会用你传入的静态初始elements数组覆盖Cytoscape实例的当前状态,你通过cy.add()新增的节点会被重置。同时你没有将Cytoscape实例持久化存储在组件中,也无法稳定拿到最新的实例调用方法。
方案1:React受控模式(推荐)
所有图数据都存在React state中,和组件生命周期完全同步,你可以直接从state获取全量最新数据,不需要依赖Cytoscape实例方法:
class MyApp extends React.Component { constructor(props){ super(props); // 初始化state存储全量图数据 this.state = { elements: [ { data: { id: 'one', label: 'Node 1' }, position: { x: 250, y: 250 } }, { data: { id: 'two', label: 'Node 2' }, position: { x: 300, y: 250 } }, { data: { source: 'one', target: 'two', label: 'Edge from Node1 to Node2' } } ] }; // 存储cytoscape实例 this.cy = null; } render(){ return <CytoscapeComponent cy = {cy => { // 保存实例到组件 this.cy = cy; cy.contextMenus({ menuItems: [ { id: 'add-node', content: 'add node', tooltipText: 'add node', image: {src: "./node_modules/cytoscape-context-menus/assets/add.svg", width: 12, height: 12, x: 6, y: 4}, coreAsWell: true, onClickFunction: (event) => { const pos = event.position || event.cyPosition; const newNode = { data: { id: `node-${Date.now()}`, // 必须给新增节点加唯一id,否则Cytoscape会报错 group: 'nodes' }, position: { x: pos.x, y: pos.y } }; // 更新state,自动同步到图 this.setState(prev => ({ elements: [...prev.elements, newNode] })); } } ] }) }} elements={this.state.elements} style={ { width: '100%', height: '40vmax'} } />; } // 调用该方法即可拿到全量图数据 getFullGraphData = () => { return this.state.elements; } }
方案2:非受控模式
如果你不需要React管理图数据,只想直接从Cytoscape实例获取最新状态,修改如下即可:
class MyApp extends React.Component { constructor(props){ super(props); // 存储cytoscape实例 this.cy = null; } render(){ const initialElements = [ { data: { id: 'one', label: 'Node 1' }, position: { x: 250, y: 250 } }, { data: { id: 'two', label: 'Node 2' }, position: { x: 300, y: 250 } }, { data: { source: 'one', target: 'two', label: 'Edge from Node1 to Node2' } } ]; return <CytoscapeComponent cy = {cy => { this.cy = cy; cy.contextMenus({ menuItems: [ { id: 'add-node', content: 'add node', tooltipText: 'add node', image: {src: "./node_modules/cytoscape-context-menus/assets/add.svg", width: 12, height: 12, x: 6, y: 4}, coreAsWell: true, onClickFunction: function (event) { var data = { id: `node-${Date.now()}`, // 必须加唯一id group: 'nodes' }; var pos = event.position || event.cyPosition; cy.add({ data: data, position: { x: pos.x, y: pos.y } }); } } ] }) }} // 非受控模式用initialElements传初始值,不要用elements属性,避免重渲染覆盖 initialElements={initialElements} style={ { width: '100%', height: '40vmax'} } />; } // 调用该方法即可拿到全量图数据 getFullGraphData = () => { return this.cy.json().elements; } }
注意:所有新增的节点必须设置唯一的id属性,否则Cytoscape.js无法正确识别节点,会导致数据获取异常
内容的提问来源于stack exchange,提问作者triceradactyl
相关产品推荐
相关产品推荐

