[英]Is it possible to call React from an html event handler
我正在使用带有 React.js 的 d3 绘图库,并且遇到了从 SVG 元素触发 onClick 事件的问题。
当我单击 SVG 中的元素时,我想要做的是调用 function(从道具中的父级传递)。 问题是SVG的元素是d3生产的,不是反应成分。 有什么办法可以使这项工作?
对于那些不熟悉 d3 的人,它提供了一种非常流畅的语法,用于从一组数据生成和更新 svg。 代码看起来像这样:
const existingNodes = d3Select('.nodes')
.selectAll('g.node')
.data(root.descendants());
const newNodes = existingNodes.enter().append('g');
newNodes
.append('circle')
.attr('onclick', (node) => 'onNodeSelected("Test")')
.attr('r', (node) => nodeRadius(node.data));
这段代码的问题是.attr('onclick', (node) => 'onNodeSelected("Test")')
的行,它正确地将onclick
属性添加到圆圈,但当然onNodeSelected
是反应组件,不能像这样访问。
为了提供一些上下文,React 组件的缩写代码如下所示:
export const HierarchyDiagram = ({ onNodeSelected, hierarchyData }) => {
useEffect(() => {
function buildSvg(root) {
...abbreviated
const existingNodes = d3Select('.nodes')
.selectAll('g.node')
.data(root.descendants());
const newNodes = existingNodes.enter().append('g');
newNodes
.append('circle')
.attr('onclick', (node) => 'onNodeSelected({node})')
.attr('r', (node) => nodeRadius(node.data));
....abbreviated
}
if (hierarchyData) {
buildSvg(hierarchyData);
}
}, [hierarchyData]);
return (
<svg width="100%" height="100%">
<g className="wrapper">
<g className="links"></g>
<g className="nodes"></g>
</g>
</svg>
);
};
如果要附加onclick
事件,请on
. 这应该有效:
.append('circle')
.on('click', (evt, node) => {
onNodeSelected(node);
d3.event.stopPropagation(); // stop the event propagation
});
我想出了一个可行的可怕解决方案。 如果其他人可以找到更好的解决方案,那么我会将您的答案标记为正确的。
我的解决方案是添加一个隐藏输入并使用它来传递被单击节点的 ID。 这是因为子元素(SVG 中的圆圈)在父元素(事件冒泡)之前收到点击。
我的缩写代码如下所示:
export const HierarchyDiagram = ({ onNodeSelected, hierarchyData }) => {
const hiddenInputId = 'selected-node-id';
useEffect(() => {
function buildSvg(root) {
...abbreviated
const existingNodes = d3Select('.nodes')
.selectAll('g.node')
.data(root.descendants());
const newNodes = existingNodes.enter().append('g');
newNodes
.append('circle')
.attr('onclick', (node) => 'getElementById("' + hiddenInputId + '").value="' + node.data.id + '"')
.attr('r', (node) => nodeRadius(node.data));
....abbreviated
}
if (hierarchyData) {
buildSvg(hierarchyData);
}
}, [hierarchyData]);
function handleClick() {
const hiddenInput = document.getElementById(hiddenInputId);
const selectedNodeId = hiddenInput.value;
hierarchyData.descendants().forEach((node) => {
if (node.data?.id === selectedNodeId) onNodeSelected(node.data);
});
}
return (
<>
<input type="hidden" id={hiddenInputId} />
<svg width="100%" height="100%">
<g className="wrapper">
<g className="links"></g>
<g className="nodes"></g>
</g>
</svg>
</>
);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.