Вопросы о событиях React
-
1. Почему ручная привязка
this
-
2.
React
В чем разница между событием и нативным событием -
3.
React
Можно ли смешивать порядок выполнения событий и собственных событий? -
4.
React
Как события разрешают кросс-браузерную совместимость -
5. Что такое синтетическое событие
Ниже приведена блок-схема, которая обобщает все процессы выполнения после того, как я прочитал исходный код. Я не буду вставлять код. Если вы хотите прочитать код, чтобы увидеть, как он реализован, вы можете найти его в исходном коде в соответствии с блок-схема.
регистрация на мероприятие
- Загрузка/обновление компонента.
- пройти через
lastProps
,nextProps
Чтобы определить, следует ли добавлять или удалять события, вызовите методы регистрации и удаления событий соответственно. - перечислить
EventPluginHub
изenqueuePutListener
для хранения событий - Получать
document
объект. - По названию события (например,
onClick
,onCaptureClick
), чтобы определить, следует ли всплывать или захватывать. - определить, есть ли
addEventListener
метод, в противном случае используйтеattachEvent
(совместимо с IE). - давать
document
Зарегистрируйте обратный вызов собственного события какdispatchEvent
(унифицированный механизм распределения событий).
хранилище событий
-
EventPluginHub
Отвечает за управление синтетическими событиями React.callback
, будетcallback
сохранить вlistenerBank
, а также сохраняетPlugin
. -
EventPluginHub
изputListener
Метод заключается в добавлении прослушивателя в контейнер хранилища. - Получить уникальный идентификатор элемента, привязанного к событию
key
. - будет
callback
Уникальная идентификация элемента на основе типа событияkey
сохранить вlistenerBank
середина. -
listenerBank
Структура:listenerBank[registrationName][key]
.
Например:
{
onClick:{
nodeid1:()=>{...}
nodeid2:()=>{...}
},
onChange:{
nodeid3:()=>{...}
nodeid4:()=>{...}
}
}
Запуск/выполнение события
Выполнение события здесь использует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
Самореализованный барботажный механизм.
синтетическое событие
- перечислить
EventPluginHub
изextractEvents
метод. - перебрать все типы
EventPlugin
(служебные методы для обработки различных событий). - в каждом
EventPlugin
Возвращает разные пулы событий в соответствии с разными типами событий. - Извлеките синтетическое событие из пула событий и создайте новое, если пул событий пуст.
- по элементу
nodeid
(Уникально идентифицируетkey
) и тип события изlistenerBink
Уберите функцию обратного вызова - Возвращает функцию обратного вызова с синтетическими параметрами события.
Общий процесс
Соедините вышеуказанные четыре процесса последовательно.
Зачем вручную привязывать это
Благодаря анализу процессов, запускаемому событиями,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>)
}
Результаты:
Из описанного выше процесса мы можем понять:
-
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
Используется пул событий, который может значительно сэкономить память без частого создания и уничтожения объектов событий.
Кроме того, независимо от того, какая среда браузера используется, браузер будет единообразно создавать тип события как синтетическое событие, чтобы достичь цели совместимости браузера.