[Подробно о реакции] Механизм событий React

React.js

Вопросы о событиях React

  • 1. Почему ручная привязкаthis

  • 2.ReactВ чем разница между событием и нативным событием

  • 3.ReactМожно ли смешивать порядок выполнения событий и собственных событий?

  • 4.ReactКак события разрешают кросс-браузерную совместимость

  • 5. Что такое синтетическое событие

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

регистрация на мероприятие

image

  • Загрузка/обновление компонента.
  • пройти черезlastProps,nextPropsЧтобы определить, следует ли добавлять или удалять события, вызовите методы регистрации и удаления событий соответственно.
  • перечислитьEventPluginHubизenqueuePutListenerдля хранения событий
  • Получатьdocumentобъект.
  • По названию события (например,onClick,onCaptureClick), чтобы определить, следует ли всплывать или захватывать.
  • определить, есть лиaddEventListenerметод, в противном случае используйтеattachEvent(совместимо с IE).
  • даватьdocumentЗарегистрируйте обратный вызов собственного события какdispatchEvent(унифицированный механизм распределения событий).

хранилище событий

image

  • EventPluginHubОтвечает за управление синтетическими событиями React.callback, будетcallbackсохранить вlistenerBank, а также сохраняетPlugin.
  • EventPluginHubизputListenerМетод заключается в добавлении прослушивателя в контейнер хранилища.
  • Получить уникальный идентификатор элемента, привязанного к событиюkey.
  • будетcallbackУникальная идентификация элемента на основе типа событияkeyсохранить вlistenerBankсередина.
  • listenerBankСтруктура:listenerBank[registrationName][key].

Например:

{
    onClick:{
        nodeid1:()=>{...}
        nodeid2:()=>{...}
    },
    onChange:{
        nodeid3:()=>{...}
        nodeid4:()=>{...}
    }
}

Запуск/выполнение события

image

Выполнение события здесь используетReactМеханизм пакетной обработки из предыдущей статьи[Подробно реагировать] механизм выполнения setStateОн уже был проанализирован в , и не будет здесь более подробно анализироваться.

  • курокdocumentРегистрация обратных вызовов для нативных событийdispatchEvent
  • Получить элемент, который запускает событие на самом глубоком уровне

Например, следующий код: first получитthis.child

      <div onClick={this.parentClick} ref={ref => this.parent = ref}>
        <div onClick={this.childClick} ref={ref => this.child = ref}>
          test
        </div>
      </div>
  • Пройдите все родительские элементы этого элемента и обработайте каждый уровень элементов по очереди.
  • Создайте синтетическое событие.
  • Сохраните синтетические события на каждом уровне вeventQueueв очереди событий.
  • траверсeventQueue.
  • пройти черезisPropagationStoppedОпределяет, выполняет ли текущее событие метод предотвращения всплытия.
  • Если всплытие предотвращено, остановите обход, в противном случае пропуститеexecuteDispatchВыполнение синтетических событий.
  • Отпустите событие о завершении обработки.

reactПереопределено в собственном синтетическом событииstopPropagationметод, будетisPropagationStoppedУстановить какtrue, а затем решить, продолжать ли выполнение в соответствии с этим обходом в процессе обхода каждого уровня событий. ЭтоreactСамореализованный барботажный механизм.

синтетическое событие

image

  • перечислитьEventPluginHubизextractEventsметод.
  • перебрать все типыEventPlugin(служебные методы для обработки различных событий).
  • в каждомEventPluginВозвращает разные пулы событий в соответствии с разными типами событий.
  • Извлеките синтетическое событие из пула событий и создайте новое, если пул событий пуст.
  • по элементуnodeid(Уникально идентифицируетkey) и тип события изlistenerBinkУберите функцию обратного вызова
  • Возвращает функцию обратного вызова с синтетическими параметрами события.

Общий процесс

Соедините вышеуказанные четыре процесса последовательно.

image

Зачем вручную привязывать это

Благодаря анализу процессов, запускаемому событиями,dispatchEventназываетсяinvokeGuardedCallbackметод.

function invokeGuardedCallback(name, func, a) {
  try {
    func(a);
  } catch (x) {
    if (caughtError === null) {
      caughtError = x;
    }
  }
}

Видно, что callback-функция вызывается напрямую, а вызываемый компонент не указывается, поэтому он получается напрямую без ручной привязки.thisдаundefined.

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

Чем оно отличается от исходного события?

  • ReactСобытия названы верблюжьим регистром, а не строчными.

  • пройти черезJSX, вы передаете функцию в качестве обработчика события, а не строку.

Например,HTML:

<button onclick="activateLasers()">
  Activate Lasers
</button>

существуетReactнемного отличается:

<button onClick={activateLasers}>
  Activate Lasers
</button>

Еще одно отличие состоит в том, что в React нельзя вернутьfalseчтобы предотвратить поведение по умолчанию. нужно вызывать явноpreventDefault.

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

ReactПорядок выполнения событий и собственных событий

  componentDidMount() {
    this.parent.addEventListener('click', (e) => {
      console.log('dom parent');
    })
    this.child.addEventListener('click', (e) => {
      console.log('dom child');
    })
    document.addEventListener('click', (e) => {
      console.log('document');
    })
  }

  childClick = (e) => {
    console.log('react child');
  }

  parentClick = (e) => {
    console.log('react parent');
  }

  render() {
    return (
      <div onClick={this.parentClick} ref={ref => this.parent = ref}>
        <div onClick={this.childClick} ref={ref => this.child = ref}>
          test
        </div>
      </div>)
  }

Результаты:

image

Из описанного выше процесса мы можем понять:

  • reactВсе события смонтированы наdocumentсередина
  • Когда срабатывает настоящий дом, он пузырится доdocumentпозжеreactобработка событий
  • Таким образом, собственное событие будет выполнено первым
  • затем выполнитьreactсинтетическое событие
  • Окончательное исполнение действительно вdocumentсобытия, установленные на

Можно ли смешивать реагирующие события и нативные события?

reactЛучше не смешивать события и нативные события.

Если выполняется в нативном событииstopPropagationметод, приведет к другимreactНедействительность события. потому что события для всех элементов не смогут всплывать доdocumentначальство.

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

Синтетические события, совместимые с браузером

  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

здесь,eявляется составным событием.Reactв соответствии с W3C Спецификация определяет это синтетическое событие, так что вам не нужно беспокоиться о кросс-браузерной совместимости.

Обработчик события доставитSyntheticEvent, который представляет собой встроенную кросс-браузерную оболочку событий. Он имеет тот же интерфейс, что и собственные события браузера, в том числеstopPropagation()иpreventDefault(), они работают одинаково во всех браузерах.

каждыйSyntheticEventВсе объекты имеют следующие свойства:

boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
DOMEventTarget target
number timeStamp
string type

ReactСинтетическийSyntheticEventИспользуется пул событий, который может значительно сэкономить память без частого создания и уничтожения объектов событий.

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

Рекомендуемое чтение