реагировать, отправлять и слушать пользовательские события - PullRequest
3 голосов
/ 30 марта 2020

Я хотел бы интегрировать веб-компоненты в свое приложение реакции. Они определяют набор настраиваемых событий, которые должно обрабатывать приложение реагирующего приложения.

Согласно реагирующим документам :

События, испускаемые веб-компонентом, могут не распространяется должным образом через дерево рендеринга React. Вам нужно будет вручную подключить обработчики событий для обработки этих событий в ваших компонентах React.

Я изо всех сил пытался сделать эту работу. Я могу отправлять пользовательские события из реагирующих компонентов и слушать их на элементах dom. Но я не могу перехватить эти события на других компонентах реагирования.

Как правильно прослушать настраиваемые события (и в идеале также иметь возможность их отправлять) из приложения реагирования?

Минимальный пример :

Я создал минимальный пример ( edit live на sandbox.io ). Он состоит из двух элементов div, внешний слушает мое пользовательское событие, а внутренний - виртуальный dom. В виртуальном домике есть два компонента. Внешний слушает пользовательское событие, внутренний отправляет его. При запуске внешний div регистрирует пользовательское событие. Внутри приложения реагирования оно не перехватывается.

Если вы хотите поиграться с кодом, я настроил его как репо:

git clone https://github.com/lhk/react_custom_events
cd react_custom_events
npm i
npm run start
# browser opens, look at the console output

index.html, содержит div, который будет прослушивать пользовательские элементы dom, а внутри него находится root приложения реагирования.

<div id='listener'>
  <div id="react_root"></div>
</div>

Приложение реагирования состоит из двух функциональных компонентов: Listener и Dispatcher. index.tsx визуализирует приложение реагирует и устанавливает прослушиватель на dom div:

document.getElementById("listener")?.addEventListener("custom", ev => {
  console.log("dom received custom event");
});

ReactDOM.render(<Listener />, document.getElementById("react_root"));

И вот два компонента, которые отправляют и прослушивают пользовательское событие dom. Listener.tsx:

import React, { useEffect, useRef } from "react";
import Dispatcher from "./Dispatcher";

export default function Listener() {
  const divRef = useRef(null);
  useEffect(() => {
    (divRef.current as any).addEventListener("custom", (ev:any) => {
        console.log("react received custom event");
      });
  });
  return (
    <div ref={divRef}>
      <Dispatcher />
    </div>
  );
}

Dispatcher.tsx:

import React, { useEffect, useRef } from "react";
import { customEvent } from "./events";

export default function Dispatcher() {
  const pRef = useRef(null);
  useEffect(() => {
    (pRef.current as any).dispatchEvent(customEvent);
  });
  return (
    <div>
      <p ref={pRef}>Some Text</p>
    </div>
  );
}

Наконец, пользовательское событие объявляется так:

export var customEvent = new Event('custom', { bubbles: true });

Смежные вопросы :

Этот вопрос звучит очень похоже: Прослушивание событий веб-компонента в React

Но на самом деле речь идет не о системе пользовательских событий в реагировать. Вместо этого он спрашивает, как предоставить атрибут события в полимерном компоненте.

Этот вопрос также касается пользовательских событий, но не в контексте реакции: Как прослушивать пользовательские события, определенные веб-компонентом

Этот вопрос кажется синтаксической ошибкой: addEventListener в приложении React не работает

1 Ответ

0 голосов
/ 30 марта 2020

Мне кажется, что это просто невозможно в реакции.

React предлагает систему синтетических c событий. Это было реализовано из соображений совместимости, события syntheti c предоставляют один и тот же API для всех браузеров. Внутренне, реакция включает собственные события DOM в события syntheti c.

Однако эти события syntheti c также вводят ряд ограничений:

  • syntheti c события don не освещать все родные события. В частности, есть изменения вокруг onInput и onChange.
  • нет синтетических c версий пользовательских событий
  • нативные (пользовательские) события будут пузыриться через виртуальный дом, не вызывая каких-либо слушателей событий , Покинув виртуальный дом, они продолжат пузыриться через оставшийся дом. Это то, что происходит в моем примере кода.
  • невозможно отправить синтетические c события самостоятельно

Возможно прослушать пользовательские события в виртуальном домене, но только на том же элементе, который их отправляет . Следующий код перехватит событие:

export default function Dispatcher() {
  const pRef = useRef(null);
  useEffect(() => {
    (pRef.current as any).addEventListener('custom', ()=>{
      console.log('react caught custom event directly on component');
    });
    (pRef.current as any).dispatchEvent(customEvent);
  });
  return (
    <div>
      <p ref={pRef}>Some Text</p>
    </div>
  );
}

Я бы сказал, что это делает пользовательские события практически бесполезными. Если вам нужно получить ссылку на указанный узел c dom, который вызвал пользовательское событие, вы можете также сделать его обратным вызовом.

Если вы хотите прочитать об этом, существует множество проблем с github. К сожалению, команда реагирования в Facebook, похоже, довольно сильно их смягчает. Они просто закрываются без дальнейших комментариев: (

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...