You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS中Bumbeishvili D3-Org-Chart布局与数据更新异常问题

D3-org-chart + React 功能问题排查

问题概述

已在CodeSandbox上复现并简化问题,当前存在以下问题:

1.(已解决)布局切换后节点展开/折叠异常

点击顶部切换布局按钮后,再点击节点展开/折叠按钮,图表会恢复至原始左到右布局,第二次点击才会执行预期的展开/折叠操作。相关代码:

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;

2. 数据集切换异常

点击切换开关后,需要点击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未正确清理旧内容有关,可能存在重复渲染或状态未正确保存/更新的情况。

已尝试未成功的方法

  • 使用d3-org-chart的.connectionsUpdate()、.linkUpdate()、.nodeContent()、.nodeUpdate()、.updateNodesState()和.update()方法(不确定是否正确使用)
  • 组合使用d3的select()、selectAll()、enter()、append()、join()、merge()、exit()和remove()方法
  • 使用React的useState()、useRef()、useCallback()、useEffect()、useLayoutEffect()和forwardRef()钩子

期望目标

除非刷新页面,否则点击按钮时图表不会恢复至原始布局;点击切换数据集按钮能即时正确更新节点;优先使用d3-org-chart方法解决,也接受其他可行方案。


内容的提问来源于stack exchange,提问作者God Industries

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:12:39