繁体   English   中英

是否可以从 html 事件处理程序调用 React

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM