Можно ли вызвать React из обработчика событий html

Я использую библиотеку рисования d3 с React.js и столкнулся с проблемой запуска событий onClick из элементов SVG.

Что я хочу сделать, так это вызвать функцию (переданную от родителя в реквизитах), когда я нажимаю на элемент в SVG. Проблема в том, что элементы 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>
  );
};

Где вы разместили код выше? в боковом компоненте?

Vaibhav 15.12.2020 05:15

Я отредактировал свой вопрос, чтобы предоставить больше контекста для того, как этот код называется

bikeman868 15.12.2020 19:00
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
2
154
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я придумал ужасное решение, которое действительно работает. Если кто-то еще найдет лучшее решение, я отмечу ваш ответ как правильный.

Мое решение состояло в том, чтобы добавить скрытый ввод и использовать его для передачи идентификатора узла, который был нажат. Это работает, потому что дочерний элемент (круг в 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>
    </>
  );
};
Ответ принят как подходящий

Если вы хотите прикрепить событие onclick, используйте on. Это должно работать:

.append('circle')
.on('click', (evt, node) => {
  onNodeSelected(node);
  d3.event.stopPropagation(); // stop the event propagation
});

Это очень близко, но не совсем там. Когда я устанавливаю точку останова, я вижу, что node имеет тип MouseEvent, но мне нужен доступ к данным.

bikeman868 16.12.2020 01:12

Я обнаружил, что this.__data__.data действительно дает мне доступ к данным и, возможно, лучший хак, чем решение для скрытого ввода. Есть ли менее хакерский способ сделать это?

bikeman868 16.12.2020 01:22

Обработчик события должен быть (evt, node) => вместо (node) =>. Я обновил ответ, который теперь работает как положено.

bikeman868 16.12.2020 01:32

Да, спасибо! Я не обращал внимания на часть аргументов, но теперь ответ выглядит намного лучше.

lissettdm 16.12.2020 03:04

Другие вопросы по теме