Реакция синтетических событий, не работающих в веб-компоненте - PullRequest
3 голосов
/ 13 мая 2019

Я следовал документации React о том, как использовать React внутри веб-компонента (https://reactjs.org/docs/web-components.html)), но обнаружил, что синтетическая система событий просто не работает для дерева React внутри этого компонента React.

Вот JS Fiddle , где вы можете попробовать:

  • Компонент React, встроенный естественным образом без веб-компонентов
  • Тот же компонент React, встроенный в веб-компонент (события не срабатывают)
  • Другой компонент React, который подключает прослушиватели событий вручную, внутри веб-компонента
class CounterWithSyntheticEvents extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0,
        };
    }

    handleClick() {
        this.setState(prevState => ({ counter: prevState.counter + 1 }));
    }

    render() {
        return (
            <div>
                Count {this.state.counter} <button onClick={this.handleClick.bind(this)}>+</button>
            </div>
        );
    }
}
class CounterWithDOMEvents extends React.Component {
    constructor(props) {
        super(props);
        this.buttonRef = React.createRef();
        this.state = {
            counter: 0,
        };
    }

    componentDidMount() {
        const listenerFn = this.handleClick.bind(this);
        this.buttonRef.current.addEventListener("click", listenerFn);
      this.removeListener = () => this.buttonRef.current.removeEventListener('click', listenerFn);
    }

    componentWillUnmount() {
        this.removeListener();
    }

    handleClick() {
        this.setState(prevState => ({ counter: prevState.counter + 1 }));
    }

    render() {
        return (
            <div>
                Count {this.state.counter} <button ref={this.buttonRef}>+</button>
            </div>
        );
    }
}

ReactDOM.render(<CounterWithSyntheticEvents />, document.getElementById("container"));

class ReactSyntheticEvents extends HTMLElement {
    connectedCallback() {
        const mountPoint = document.createElement("div");

        const shadow = this.attachShadow({ mode: "open" });
        shadow.appendChild(mountPoint);
        ReactDOM.render(<CounterWithSyntheticEvents />, mountPoint);
    }
}
customElements.define("react-synthetic-events", ReactSyntheticEvents);

class ReactDOMEvents extends HTMLElement {
    connectedCallback() {
        const mountPoint = document.createElement("div");

        const shadow = this.attachShadow({ mode: "open" });
        shadow.appendChild(mountPoint);
        ReactDOM.render(<CounterWithDOMEvents />, mountPoint);
    }
}

customElements.define("react-dom-events", ReactDOMEvents);
<div id="container"></div>
<react-synthetic-events ></react-synthetic-events>
<react-dom-events ></react-dom-events>

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

Кто-нибудь знает о быстром исправлении, которое я мог бы сделать, чтобы события распространялись на компоненты? (чтобы 2-й корпус скрипки работал)

Я слышал о Реакция полимера , но еще не попробовал. И я хотел бы не вводить другой слой, если это возможно.

Ответы [ 2 ]

1 голос
/ 13 мая 2019

Согласно документам React.

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

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

0 голосов
/ 27 мая 2019

Я потратил некоторое время, пытаясь найти исправление или обходной путь, и вот результат:

  • Ошибка идентифицирована и решение найдено: React должен разрешить несколько корней слушателей,это должны быть «контейнеры», а не только документ: https://github.com/facebook/react/issues/2043. Была предпринята, по крайней мере, более одной попытки исправить это, но кажется, что в конце не было никакого исправления, после более чем двух лет: https://github.com/facebook/react/issues/2043#issuecomment-346039823. Похоже, что это не будет исправлено, если мы не внесем свой вклад, или Facebook не начнет изучать веб-компоненты!
  • Некоторая активность в StackOverflow ( Событие Click не срабатывает, когда React Component втеневой DOM ) привел к внедрению обходного пути (https://www.npmjs.com/package/react-shadow-dom-retarget-events).). Техническая реализация может быть обобщена как пробная копия системы обработки событий React на уровне теневого корня веб-компонента, за исключением того, чтодействительно упрощен. Когда я попробовал его на своего рода сценарии использования, он работал для некоторых компонентов пользовательского интерфейса (флажок, текстовое поле), нона некоторых других (тумблер).Для переключения (из пользовательского интерфейса материала) я получал два события вместо одного.В любом случае, я считаю, что попытка реплицировать даже систему React с помощью пары строк кода не является надежным обходным путем.
  • Наконец, я обнаружил пару библиотек, которые утверждают, что упростить использование React с помощьюВеб-компоненты, но они на самом деле имеют дело с «поверхностью» веб-компонента, а не внутри него, и поэтому не решают проблему.Я попробовал https://github.com/skatejs/val и https://www.npmjs.com/package/web-react-components. Я нашел последний наиболее интересным (простым и точным).

В итоге, в заключение, мырешил использовать веб-компоненты без функции Shadow-DOM.

...