我已经在 CodeSandbox 上复制并简化了我的问题,可以在此处查看:https://codesandbox.io/p/sandbox/d3-org-chart-react-function-org-chart-gvfz4l?file=%2Fsrc %2Fcomponents%2FdataToggle.js%3A9%2C11
当前的问题是...
- (已解决)如果顶部的交换布局按钮已被点击并且节点的展开/折叠按钮被点击,则图表默认返回其原始布局(在本例中为从左到右的布局层次结构)。第二次单击节点的展开/折叠按钮时,它将实际执行所需的展开/折叠。相关代码显示在这里...
//swapButton.js
const SwapButton = forwardRef(({ onSwapLayout }, ref) => {
// const [isCycleLayoutOn, setIsCycleLayoutOn] = useState(false);
const swapLayout = (event) => {
event.preventDefault();
onSwapLayout(event);
};
return (
<div>
<button
className="context-menu-btns"
style={{
backgroundColor: "#4caf50",
color: "white",
borderRadius: "0.5rem",
paddingTop: "0.5rem",
paddingBottom: "0.5rem",
paddingLeft: "1rem",
paddingRight: "1rem",
}}
onClick={(event) => swapLayout(event)}
ref={ref}
>
<FaRetweet size="2rem" />
</button>
</div>
);
});
export default SwapButton;
//orgChart.js
const OrganizationalChart = (props) => {
const d3Container = useRef(null);
const chartRef = useRef(null);
const [layoutIndex, setLayoutIndex] = useState(0);
const handleSwapLayout = useCallback((event) => {
if (event) {
setLayoutIndex((prevIndex) => (prevIndex + 1) % 4);
return layoutIndex;
}
return layoutIndex;
});
useLayoutEffect(() => {
const handleLayout = () => handleSwapLayout();
const chart = new OrgChart();
if (props.data && d3Container.current) {
chart
.container(d3Container.current)
.data(props.data)
.nodeWidth((d) => 300)
.nodeHeight((d) => 150)
.layout(["left", "top", "right", "bottom"][handleLayout()])
.compactMarginBetween((d) => 80)
.onNodeClick((d) => {
toggleDetailsCard(d);
})
.buttonContent((node, state) => {
return ReactDOMServer.renderToStaticMarkup(
<CustomExpandButton {...node.node} />
);
})
.nodeContent((d) => {
return ReactDOMServer.renderToStaticMarkup(
<CustomNodeContent {...d} />
);
})
.render();
chartRef.current = chart;
}
}, [props, props.data, handleSwapLayout]);
return (
<div style={styles.orgChart} ref={d3Container}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
padding: "0.5rem",
}}
>
<SwapButton onSwapLayout={handleSwapLayout} ref={d3Container} />
</div>
);
};
export default OrganizationalChart;
- 如果单击切换开关,则需要单击更改数据集按钮 3-4 次才能更新节点。当它更新时,它最终会向后更新。此外,当单击展开/折叠按钮时,它将返回到原来的布局。
//dataToggle.js
const DataToggle = ({ onDataChange, isToggleOn }) => {
const handleChange = (event) => {
event.preventDefault();
onDataChange(event);
};
return (
<div>
<span className={!isToggleOn ? "label_txt_unchecked" : "label_txt"}>OFF</span>
<label className="switch">
<input
checked={isToggleOn}
type={"checkbox"}
onChange={(event) => handleChange(event)}
/>
<span className="slider"></span>
</label>
<span className={isToggleOn ? "label_txt_checked" : "label_txt"}>ON</span>
</div>
);
};
export default DataToggle;
//App.js
const App = () => {
const [data, setData] = useState(employees);
const [isToggleOn, setIsToggleOn] = useState(false);
const handleDataChange = (event) => {
event.preventDefault();
setIsToggleOn(!isToggleOn);
if (isToggleOn) {
setData(revisedEmployees);
} else {
setData(employees);
}
};
return (
<React.StrictMode>
<>
<h1 style={styles.title}>Organization Chart</h1>
<div>
<DataToggle onDataChange={handleDataChange} isToggleOn={isToggleOn}/>
</div>
<OrganizationalChart data={data} />
</>
</React.StrictMode>
);
};//
export default App;
我怀疑这些问题与向 DOM 添加新信息而没有正确清除 DOM 中的旧信息有关。感觉就像它正在尝试渲染两个不同的图表或未正确保存/更新。
我已经尝试过使用...
d3-org-chart
方法:.connectionsUpdate()
、.linkUpdate()
、.nodeContent()
、.nodeUpdate()
、.updateNodesState()
和.update()
》没有成功(我什至不相信我是否正确使用了它们)。这是我获取 d3-org-chart 的地方:https://github.com/bumbeishvili/org-chart?tab=readme-ov-file
d3
方法的不同组合,例如.select()
、.selectAll()
、.enter()
、.append()
、.join()
、.merge()
、.exit()
和.remove()
...全部都带有没有成功。
useState()
、useRef()
、useCallback()
、useEffect()
、useLayoutEffect()
和forwardRef()
——没有成功。
我开始这个项目的原始模板在这里:https://codesandbox.io/s/org-chart-fnx0zi?file=/src/components/orgChart.js
理想情况下,我希望图表在按钮或单击时不呈现其原始布局,除非刷新网页。此外,我希望不需要单击 3-4 次更改数据集按钮即可在正确的父节点下更新节点位置。如果有一种方法可以通过
d3-org-chart
方法完成更新,我会更喜欢。然而,考虑到我在 4 个月的时间里还没有找到解决方案,我会采取任何解决方案。
要解决问题 #1,请将
const chartRef = useRef(new OrgChart())
放在开头,然后从 const chart = new OrgChart()
中删除 useLayoutEffect()
。
根据bumbeishvili的作者
d3-org-chart
的说法,这是使用react时常见的错误。他在此 CodeSandbox 中解决了这个问题: