reactjs - 如何在 React.StrictMode 中重新加热 d3 力模拟?
我已经决定在 React 中使用 D3 创建一个交互式力导向图,一切在仿真开始后都能正常工作,但在 React 严格模式下拖动功能不起作用。我认为这一定是由于 React StrictMode 18 中组件的挂载和重新挂载造成的,但我无法真正确定原因。
我的 useEffect 钩子的内容在哪里
useEffect(function () {
if (!svgRef.current) return;
const svg = d3.select(svgRef.current);
const nodes = d3.map(
props.nodes,
(node): Node => ({
...node,
})
);
const links = d3
.map(props.links, (link) => ({
source: nodes.find((node) => node.id === link.source),
target: nodes.find((node) => node.id === link.target),
}))
.filter(
(link): link is { source: Node; target: Node } =>
link.source !== undefined && link.target !== undefined
);
const simulation = d3
.forceSimulation(nodes)
.force(
"link",
d3
.forceLink(links)
.id((_, i) => nodes[i].id)
.distance(LINK_LENGHT)
)
.force("charge", d3.forceManyBody().strength(-NODE_REPULSION))
.force("center", d3.forceCenter())
.force("forceX", d3.forceX().strength(NODE_GRAVITY))
.force("forceY", d3.forceY().strength(NODE_GRAVITY))
.force("colide", d3.forceCollide(NODE_RADIUS * NODE_MARGIN))
.on("tick", ticked);
const link = svg
.selectAll("line")
.data(links)
.enter()
.append("line")
.style("stroke", "#aaa");
const node = svg
.selectAll("circle")
.data(nodes)
.enter()
.append("circle")
.call(
d3
.drag<SVGCircleElement, Node>()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
)
.attr("fill", (node) => node.color))
.attr("r", NODE_RADIUS)
.attr("stroke", "#000000")
.attr("stroke-width", 1);
function ticked() {
link
.attr("x1", (d) => d.source.x!)
.attr("y1", (d) => d.source.y!)
.attr("x2", (d) => d.target.x!)
.attr("y2", (d) => d.target.y!);
node.attr("cx", (d) => d.x!).attr("cy", (d) => d.y!);
}
function dragstarted(event: any, d: Node) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event: any, d: Node) {
console.log(simulation.alpha());
d.fx = event.x;
d.fy = event.y;
}
function dragended(event: any, d: Node) {
if (!event.active) simulation.alphaTarget(0.0001);
d.fx = null;
d.fy = null;
}
},
[props.nodes.length, props.links.length]
)
任何线索或帮助都将不胜感激。
答案#1
由于在移除 StrictMode 后它可以正常工作,我推测我需要在我的 useEffect 中添加一个清理函数。结果发现我只需要像这样移除我插入的链接和节点。
return () => {
node.remove();
link.remove();
}
