React结合D3 org-chart库自定义节点组件返回[object Object]如何解决
问题原因
你遇到的{object Object}报错是因为d3-org-chart的nodeContent配置项默认接收HTML字符串作为返回值,直接传入React组件实例本质是传入JS对象,对象被强制转为字符串时就会呈现{object Object}。
解决方案
方案1:静态组件用renderToString转HTML(无复杂交互场景)
如果你的自定义节点组件没有点击、输入这类交互需求,直接用React服务端渲染能力把组件转成HTML字符串传入即可:
import { renderToString } from 'react-dom/server'; // 配置节点内容时使用 const orgChart = new OrgChart() .nodeContent(d => { // 把自定义组件转为HTML字符串返回 return renderToString(<TestOrgCard nodeData={d} />) })
方案2:挂载React实例到DOM节点(保留交互能力)
如果组件需要保留交互事件,你可以先给每个节点预留空DOM容器,再把React组件渲染到对应容器中:
- 先在
nodeContent中返回带唯一标识的空容器
.nodeContent(d => { return `<div class="org-node-card" data-node-id="${d.id}"></div>` })
- 监听图表更新事件,把自定义组件渲染到对应容器
React 17及更早版本写法:
import { render } from 'react-dom'; // 图表初始化完成后添加更新回调 orgChart.on('render', () => { document.querySelectorAll('.org-node-card').forEach(container => { const nodeId = container.dataset.nodeId; // 拿当前节点的全量数据 const currentNodeData = orgChart.get(nodeId); // 渲染React组件到容器 render(<TestOrgCard data={currentNodeData} />, container); }) })
React 18及以上版本写法:
import { createRoot } from 'react-dom/client'; // 全局存储所有节点的root实例避免内存泄漏 const nodeRootMap = new Map(); orgChart.on('render', () => { // 先清理已销毁节点的root实例 nodeRootMap.forEach((root, nodeId) => { if (!document.querySelector(`[data-node-id="${nodeId}"]`)) { root.unmount(); nodeRootMap.delete(nodeId); } }) // 渲染当前存在的节点 document.querySelectorAll('.org-node-card').forEach(container => { const nodeId = container.dataset.nodeId; const currentNodeData = orgChart.get(nodeId); if (!nodeRootMap.has(nodeId)) { const root = createRoot(container); nodeRootMap.set(nodeId, root); } nodeRootMap.get(nodeId).render(<TestOrgCard data={currentNodeData} />); }) })
注意事项
- 图表每次展开折叠、缩放重绘后都会触发render事件,会自动更新新增节点的组件内容
- 组件卸载时需要遍历
nodeRootMap调用所有root的unmount方法,避免内存泄漏
内容的提问来源于stack exchange,提问作者Tobias KKS
相关产品推荐
相关产品推荐

