[Длинная статья с осторожностью] Поймите принцип механизма событий реакции в одной статье

React.js

написать впереди

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

контур

В основном он разделен на 4 части, в основном объединенные с исходным кодом.react 事件机制的原理Анализ, я надеюсь, вы сможете лучше понять и понять механизм событий реакции.

Конечно, определенно есть места, где выражение неясно или понимание недостаточно стандартно.

01 - Первоначальное понимание и проверка механизма события

02 - Понимание композиции

03 - Механизм регистрации события

04 - Механизм выполнения события

01 02 - это теоретическая чушь, а также мое личное резюме.Если вам не интересно, вы можете сразу перейти к 03 - Механизм выполнения событий.

пс:Эта статья основана на реакции 15.6.1 для анализа.Хотя это не последняя версия, она не повлияет на наше общее понимание и понимание механизма событий реакции.

Предварительное понимание и проверка механизма события

правильноreact 事件机制Репрезентативное понимание, проверка, значение и отражение.

Репрезентативное понимание

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

Все мы знаем, что все события реакции не привязаны к конкретным узлам dom, но привязаны к документу, а затем обрабатываются унифицированным обработчиком событий, который также основан на механизме событий браузера (пузырьковое), все события узла запускаются на документ.

Так как уже естьreact事件базовое познание, правильно ли это познание? Мы можем проверить это простым способом.

проверять

Подтвердить содержимое:

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

componentDidMount(){ 

        document.getElementById('btn-reactandnative').addEventListener('click', (e) => {
            console.log('原生+react 事件:   原生事件执行');
        });

    }

    handleNativeAndReact = (e) => {
        console.log('原生+react 事件:  当前执行react事件');
    }

    handleClick=(e)=>{
        console.log('button click');
    }
 render(){
        return <div className="pageIndex"><p>react event!!!</p
                <button id="btn-confirm" onClick={this.handleClick}>react 事件</button>

                <button id="btn-reactandnative" onClick={this.handleNativeAndReact}>原生 + react 事件</button>
        </div>
    }

код на двоихbuttonПривязать синтетическое событие, отдать его отдельноbtn#btn-reactandnativeРодное событие привязано.

тогда посмотри наchromeКонсоль для просмотра событий, зарегистрированных на элементе.

После простой проверки видно, что все события привязаны к разным типам событий.documentВыше триггерная функция равномерноdispatchEvent.

Только представь

Если к узлу привязаны как синтетические, так и нативные события, каково отношение выполнения после запрета всплытия?

На самом деле ответ уже читался здесь. Теперь мы анализируем эту взаимосвязь на основе наших текущих знаний.

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

** вывод:**

Собственные события, предотвращающие всплытие, определенно предотвратят срабатывание синтетических событий.

Предотвращение всплытия синтетических событий не влияет на собственные события.

Зачем? Сначала вспомните механизм событий браузера

Выполнение событий браузера должно пройти три этапа: этап захвата — этап целевого элемента — этап всплытия.

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

Поскольку аборигены заблокированы от пузырения, что еще делает синтез?

Ну на синтете очередь заблокировать от бубнения, родной будет выполняться? Конечно, будет.

Поскольку собственное событие предшествует синтетическому выполнению, все, что предотвращается в синтетическом событии, — это всплывающее всплывающее окно синтетического события. (код не буду выкладывать)

Итак, сделайте вывод:

Собственные события (блокировка всплытия) предотвращают выполнение синтетических событий.

Синтетические события (блокирующие всплывающие окна) не препятствуют выполнению собственных событий.

Лучше не смешивать их, чтобы избежать странных проблем.

значение

В чем смысл реакции, которая так много делает сама по себе?

  1. Сократите потребление памяти, повысьте производительность, не нужно регистрировать так много событий, тип события регистрируется в документе только один раз.

  2. Унифицируйте спецификацию, решите проблему совместимости событий ie и упростите логику событий.

  3. дружественный к разработчикам

считать

Поскольку React так много сделал для нас, какой механизм стоит за ним?

Как событие регистрируется, как событие запускается и как реализуется механизм всплытия?

Пожалуйста, продолжайте оглядываться назад...  

понимание синтеза

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

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

  1. Инкапсуляция нативных событий

  2. Обновления и модификации некоторых собственных событий

  3. Совместимая обработка событий из разных браузеров

Инкапсуляция нативных событий

Приведенный выше код предназначен для добавления элементаclickМетод обратного вызова события, параметры в методеe, на самом деле это не нативный объект события, а объект, обернутый реакцией, и нативный объект события помещается в свойствоe.nativeEventВнутри.

Через отладку посмотрите этот параметр в стеке выполненияeКакие свойства включены

Взгляните на официальную документацию

SyntheticEvent — это базовый класс реагирующих синтетических событий, который определяет основные общедоступные свойства и методы синтетических событий.

React будет использовать различные объекты синтетических событий в соответствии с текущим типом события, такие как автономные события мыши — SyntheticMouseEvent, события фокуса — SyntheticFocusEvent и т. д., но все они наследуются от SyntheticEvent.

Обновление и трансформация нативных событий

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

Вот пример для иллюстрации:

Когда мы объявляем событие onChange на входе, что делает для нас реакция?

Вы можете видеть, что react регистрирует не только событие onchange, но и многие другие события.

В это время, когда мы вводим содержимое в текстовое поле, мы можем получать содержимое в режиме реального времени.

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

пс:В красной стрелке выше есть недопустимое событие, которое зарегистрировано не на документ, а на конкретный элемент. Насколько я понимаю, это новое событие в html5. Оно автоматически срабатывает, когда входные данные не соответствуют правилам проверки. Однако правила проверки и конфигурация должны быть записаны на текущем элементе ввода. Если это событие зарегистрировано на документ, он будет недействителен.

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

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

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

Это мое понимание термина «синтез реакции», на самом деле обработки в реакции еще много, я просто дал несколько каштанов, а затем начал говорить о механизме регистрации событий и диспетчеризации событий.

механизм регистрации событий

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

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

Грубый процесс

Процесс регистрации событий реакции на самом деле делает две вещи: регистрацию событий и их хранение.

а) Регистрация события - на этапе монтирования компонента, в соответствии с заявленным типом события в компоненте - onclick, onchange и т.д., добавить в документ событие - addEventListener, и указать единый обработчик события dispatchEvent.

б) Хранилище событий — это хранение всех событий в реагирующем компоненте единообразно в объекте и их кэширование, чтобы можно было найти соответствующий метод для выполнения при запуске события.

ключевой шаг

Две цели, которые необходимо выполнить для регистрации события, примерно описаны выше.Какую ключевую обработку необходимо выполнить в процессе выполнения целей?

Сначала реакция получает виртуальный дом монтируемого компонента (фактически объект элемента реакции), а затем обрабатываетreact domprops определяют, есть ли свойство, объявленное как событие в свойстве, напримерonClick,onChange, на этот раз получите тип событияclick,changeи соответствующий обработчик событияfn, а затем выполните следующее3步

а. Завершите регистрацию на мероприятие

б) будетreact dom, тип события, функция-обработчикfnпоместить в хранилище массива

в) После монтирования компонента обработайте массив, сгенерированный на шаге б, и сохраните функцию обработчика событий вlistenerBank(一个对象)середина

Анализ исходного кода

из jsx

Посмотрите на самый знакомый код, который также является нашим ежедневным методом написания.

    //此处代码省略
    handleFatherClick=()=>{

    }

    handleChildClick=()=>{

    }

    render(){
        return <div className="box">
                    <div className="father" onClick={this.handleFatherClick}>
                        <div className="child" onClick={this.handleChildClick}>child </div>
                    </div>
               </div>
    }

проходить черезbabelПосле компиляции вы можете видеть, что окончательный метод называетсяreact.createElement, z, а объявленный тип события и обратный вызов — этоprops.

react.createElementРезультат выполнения вернет так называемый виртуальный дом (объект элемента реакции)

Обработка свойств компонента, получение типа события и обратного вызова fn

ReactDOMComponentПри загрузке компонентов (mountComponent) и обновлении (updateComponent) необходимо обработать пропсы (_updateDOMProperties):

Вы можете взглянуть на содержимое RegistrationNameModules, не будем вдаваться в подробности, это встроенная константа.

Регистрация событий и хранение событий

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

Затем приведенный выше код выполняется для этого метода

enqueuePutListener(this, propKey, nextProp, transaction);

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

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

源码文件:ReactBrowerEventEmitter.js

окончательное исполнениеEventListener.listen(冒泡)илиEventListener.capture(捕获), просто посмотрите на всплывающую регистрацию, это на самом делеaddEventListenerТретий параметрfalse.

Вы также можете видеть, что он также совместим с браузерами IE при регистрации событий.

не видно вышеdispatchEventОпределение , вы можете видеть входящиеdispatchEventкод метода.

Регистрация на мероприятие осуществляется здесь.

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

Запускаем хранилище событий.В реакте все события срабатывают черезdispatchEventМетод диспетчеризируется единообразно, вместо того, чтобы напрямую прописывать объявленный callback при регистрации, посмотрим, как он хранится.

reactСвяжите все события с типами событий и компонентами реагирования и сохраните эту связь вmap, то есть в объекте (паре ключ-значение), а затем при срабатывании события, согласно текущему组件idи事件类введите, чтобы найти соответствующий事件fn.

Объедините исходный код:

function enqueuePutListener(inst, registrationName, listener, transaction) {

  var containerInfo = inst._hostContainerInfo;
  var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE;
  var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument;
  listenTo(registrationName, doc);//这个方法上面已说完


  //这里涉及到了事务,事物会在以后的章节再介绍,主要看事件注册
  //下面的代码是将putListener放入数组,当组件挂载完后会依次执行数组的回调。也就是putListener会依次执行
  transaction.getReactMountReady().enqueue(putListener, {
    inst: inst,//组件实例
    registrationName: registrationName,//事件类型 click
    listener: listener //事件回调 fn
  });
}

function putListener() {
  var listenerToPut = this;
  //放入数组,回调队列
  EventPluginHub.putListener(listenerToPut.inst, listenerToPut.registrationName, listenerToPut.listener);
}

Общий процесс заключается в выполненииlistenTo(事件注册), затем выполнитеputListenerметод хранения событий, все события будут храниться в объекте —listenerBank, в частности,EventPluginHubсправляться.

 //拿到组件唯一标识 id
    var getDictionaryKey = function getDictionaryKey(inst) {

      return '.' + inst._rootNodeID;

    }

   putListener: function putListener(inst, registrationName, listener) {

    //得到组件 id
        var key = getDictionaryKey(inst);

        //得到listenerBank对象中指定事件类型的对象
        var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {});

        //存储回调 fn
        bankForRegistrationName[key] = listener;

        //....
  }

listenerBankНа самом деле это вторичкаmap, такая структура более удобна для поиска событий.

Идентификатор компонента здесь является уникальным идентификатором компонента, а затем он связан с fn, а обратный вызов связанного события можно найти на этапе триггера.

Эта структура кажется знакомой? Это объект, который мы обычно используем.

Общий процесс здесь завершен, вы чувствуете, что вас немного поняли, но не очень ясно?

Не беда, давайте сделаем подробный снимок и заново разберемся.

механизм выполнения события

На этапе регистрации события все события и типы событий будут сохранены вlistenerBankсередина.

Итак, какая польза от вышеуказанного объекта в процессе запуска событий?

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

Грубый процесс

Процесс запуска события сводится к следующим основным шагам:

1. Введите унифицированную функцию отправки событий (dispatchEvent)

2. Объедините нативные события, чтобы найти объект ReactDOMComponent, соответствующий текущему узлу.

3. Старт事件的合成

3.1 Создать указанный синтетический объект на основе текущего типа события

3.2 Инкапсуляция нативных событий и механизмов всплытия

3.3 Найти текущий элемент и всех его родителей

3,4 дюймаlistenerBankНайдите обратные вызовы событий и синтезируйте ихevent(Составное событие заканчивается)

4. Пакетная обработка событий обратного вызова в синтетических событиях (окончание завершения триггера события)

взять каштан

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

handleFatherClick=(e)=>{
        console.log('father click');
    }

    handleChildClick=(e)=>{
        console.log('child click');
    }

    render(){
        return <div className="box">
                    <div className="father" onClick={this.handleFatherClick}> father
                        <div className="child" onClick={this.handleChildClick}>child </div>
                    </div>
               </div>
    }
    

Видя этот знакомый код, мы уже знаем результат выполнения.

Когда я нажимаю на дочерний элемент div, одновременно срабатывает событие отца.

Анализ исходного кода

dispatchEvent для распределения событий

Введите унифицированную функцию отправки событий (dispatchEvent).

Когда я нажимаю на дочерний элемент div, браузер фиксирует событие в это время, и после всплытия событие всплывает в документ и передается для обработки унифицированному обработчику событий dispatchEvent. (В предыдущей статье мы уже говорили, что на документе зарегистрирован единый обработчик события dispatchEvent).

Найдите ReactDOMComponent

Объедините собственные события, чтобы найти соответствующий узел текущего узла.ReactDOMComponentобъект, соответствующий был зарезервирован в собственном объекте событияReactDOMComponentСсылка на экземпляр должна быть сохранена на этапе монтирования.

Взгляните на содержимое экземпляра ReactDOMComponent.

синтез событий

Синтез событий, обработка всплывающих сообщений и поиск обратных вызовов событий выполняются на этапе синтеза.

Генерация синтетических объектов

Найдите соответствующий синтетический класс в соответствии с текущим типом события, а затем сгенерируйте синтетический объект.

//进行事件合成,根据事件类型获得指定的合成类
var SimpleEventPlugin = {
    eventTypes: eventTypes,
    extractEvents: function extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
        var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
        //代码已省略....
        var EventConstructor;

        switch (topLevelType) {
            //代码已省略....
            case 'topClick'://【这里有一个不解的地方】 topLevelType = topClick,执行到这里了,但是这里没有做任何操作
                if (nativeEvent.button === 2) {
                    return null;
                }
            //代码已省略....
            case 'topContextMenu'://而是会执行到这里,获取到鼠标合成类
                EventConstructor = SyntheticMouseEvent;
                break;


            case 'topAnimationEnd':
            case 'topAnimationIteration':
            case 'topAnimationStart':
                EventConstructor = SyntheticAnimationEvent;//动画类合成事件
                break;

            case 'topWheel':
                EventConstructor = SyntheticWheelEvent;//鼠标滚轮类合成事件
                break;

            case 'topCopy':
            case 'topCut':
            case 'topPaste':
                EventConstructor = SyntheticClipboardEvent;
                break;
        }

        var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget);
        EventPropagators.accumulateTwoPhaseDispatches(event);
        return event;//最终会返回合成的事件对象
    }

Инкапсулирует нативные события и механизмы всплытия

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

/**
 * 
 * @param {obj} dispatchConfig 一个配置对象 包含当前的事件依赖 ["topClick"],冒泡和捕获事件对应的名称 bubbled: "onClick",captured: "onClickCapture"
 * @param {obj} targetInst 组件实例ReactDomComponent
 * @param {obj} nativeEvent 原生事件对象
 * @param {obj} nativeEventTarget  事件源 e.target = div.child
 */
function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {

    this.dispatchConfig = dispatchConfig;
    this._targetInst = targetInst;
    this.nativeEvent = nativeEvent;//将原生对象保存到 this.nativeEvent
    //此处代码略.....
    var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false;

    //处理事件的默认行为
    if (defaultPrevented) {
        this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
    } else {
        this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
    }


    //处理事件冒泡 ,thatReturnsFalse 默认返回 false,就是不阻止冒泡
    this.isPropagationStopped = emptyFunction.thatReturnsFalse;
    return this;
}

Ниже приведен метод обработки добавленного поведения по умолчанию и механизма всплытия.Фактически он изменяет значение атрибута текущего синтетического объекта.После вызова метода значение атрибута равно true, что предотвратит поведение по умолчанию или всплытие.

//在合成类原型上增加preventDefault和stopPropagation方法
_assign(SyntheticEvent.prototype, {
    preventDefault: function preventDefault() {
        // ....略

        this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
    },
    stopPropagation: function stopPropagation() {
        //....略

        this.isPropagationStopped = emptyFunction.thatReturnsTrue;
    }
);

Взгляните на код emptyFunction, чтобы понять

Найти все родительские экземпляры

Найдите все его родительские экземпляры в соответствии с текущим экземпляром узла и сохраните их в пути

/**
 * 
 * @param {obj} inst 当前节点实例
 * @param {function} fn 处理方法
 * @param {obj} arg 合成事件对象
 */
function traverseTwoPhase(inst, fn, arg) {
    var path = [];//存放所有实例 ReactDOMComponent

    while (inst) {
        path.push(inst);
        inst = inst._hostParent;//层级关系
    }

    var i;

    for (i = path.length; i-- > 0;) {
        fn(path[i], 'captured', arg);//处理捕获 ,反向处理数组
    }

    for (i = 0; i < path.length; i++) {
        fn(path[i], 'bubbled', arg);//处理冒泡,从0开始处理,我们直接看冒泡
    }
}

Посмотрите, как выглядит путь

Синтез событий заканчивается

Найдите обратные вызовы событий в listenerBank и синтезируйте их в событие.

Сразу после приведенного выше кода

fn(path[i], 'bubbled', arg);

Приведенный выше код вызовет следующий метод вlistenerBankОбратный вызов события находится и сохраняется в синтетическом объекте события.


/**EventPropagators.js
 * 查找事件回调后,把实例和回调保存到合成对象内
 * @param {obj} inst 组件实例
 * @param {string} phase 事件类型
 * @param {obj} event 合成事件对象
 */
function accumulateDirectionalDispatches(inst, phase, event) {
    var listener = listenerAtPhase(inst, event, phase);
    if (listener) {//如果找到了事件回调,则保存起来 (保存在了合成事件对象内)
        event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);//把事件回调进行合并返回一个新数组
        event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);//把组件实例进行合并返回一个新数组
    }
}

/**
 * EventPropagators.js
 * 中间调用方法 拿到实例的回调方法
 * @param {obj} inst  实例
 * @param {obj} event 合成事件对象
 * @param {string} propagationPhase 名称,捕获capture还是冒泡bubbled
 */
function listenerAtPhase(inst, event, propagationPhase) {
    var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase];
    return getListener(inst, registrationName);
}

/**EventPluginHub.js
 * 拿到实例的回调方法
 * @param {obj} inst 组件实例
 * @param {string} registrationName Name of listener (e.g. `onClick`).
 * @return {?function} 返回回调方法
 */
getListener: function getListener(inst, registrationName) {
    var bankForRegistrationName = listenerBank[registrationName];

    if (shouldPreventMouseEvent(registrationName, inst._currentElement.type, inst._currentElement.props)) {
        return null;
    }

    var key = getDictionaryKey(inst);
    return bankForRegistrationName && bankForRegistrationName[key];
}

Почему его можно найти?

Поскольку в inst (экземпляре компонента) есть _rootNodeID, существует соответствующая связь.

В этот момент создается объект синтеза событий, и все обратные вызовы событий сохраняются в объекте синтеза.

Пакетная обработка составных объектов событий

Пакетная обработка метода обратного вызова внутри объекта синтетического события (конец завершения триггера события).

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


//在这里执行事件的回调
runEventQueueInBatch(events);

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

Вставьте последний код, который выполняет метод обратного вызова

/**
 * 
 * @param {obj} event 合成事件对象
 * @param {boolean} simulated false
 * @param {fn} listener 事件回调
 * @param {obj} inst 组件实例
 */
function executeDispatch(event, simulated, listener, inst) {
    var type = event.type || 'unknown-event';
    event.currentTarget = EventPluginUtils.getNodeFromInstance(inst);

    if (simulated) {//调试环境的值为 false,按说生产环境是 true 
        //方法的内容请往下看
        ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event);
    } else {
        //方法的内容请往下看
        ReactErrorUtils.invokeGuardedCallback(type, listener, event);
    }

    event.currentTarget = null;
}

/** ReactErrorUtils.js
 * @param {String} name of the guard to use for logging or debugging
 * @param {Function} func The function to invoke
 * @param {*} a First argument
 * @param {*} b Second argument
 */
var caughtError = null;
function invokeGuardedCallback(name, func, a) {
    try {
        func(a);//直接执行回调方法
    } catch (x) {
        if (caughtError === null) {
            caughtError = x;
        }
    }
}

var ReactErrorUtils = {
    invokeGuardedCallback: invokeGuardedCallback,
    invokeGuardedCallbackWithCatch: invokeGuardedCallback,
    rethrowCaughtError: function rethrowCaughtError() {
        if (caughtError) {
            var error = caughtError;
            caughtError = null;
            throw error;
        }
    }
};

if (process.env.NODE_ENV !== 'production') {//非生产环境会通过自定义事件去触发回调
    if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') {
        var fakeNode = document.createElement('react');

        ReactErrorUtils.invokeGuardedCallback = function (name, func, a) {
            var boundFunc = func.bind(null, a);
            var evtType = 'react-' + name;
            fakeNode.addEventListener(evtType, boundFunc, false);
            var evt = document.createEvent('Event');
            evt.initEvent(evtType, false, false);
            fakeNode.dispatchEvent(evt);
            fakeNode.removeEventListener(evtType, boundFunc, false);
        };
    }
}

Наконец, react создает временный узел fakeNode, затем привязывает обработчик событий к этому временному элементу, затем создает пользовательское событие Event, запускает событие с помощью метода fakeNode.dispatchEvent и удаляет событие прослушивания сразу после завершения триггера.

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

Суммировать

Он в основном знакомит с принципом события реакции из общего процесса, не вдаваясь в детали исходного кода, включая обработку транзакций, детали синтеза и т. д. Кроме того, у меня также есть некоторые сомнения в процессе разборки. Я чувствую, что принцип можно сравнить.Это легко понять, но когда вы пишете это с исходным кодом, это будет казаться грязным, потому чтоreactКод слишком большой и переплетенный, и его трудно разделить. Те, кто интересуется исходным кодом, могут изучить его подробно. Конечно, я надеюсь, что эта статья может вдохновить вас. Если статья неясна или имеет проблемы, пожалуйста, оставьте сообщение. Связь, топор.

Наконец

Статья исписанная и некрасивая, а большие ребята пострадали. ^_^...

использованная литература

zhuanlan.zhihu.com/p/35468208

react.doc — это China.org/docs/events…


пожалуйста, остановись здесь

  • Я создаю чисто техническую группу обмена с целью обучения, общения, мышления и улучшения способностей, потому что обучение само по себе не так хорошо, как обучение со всеми, и чем больше обменов, тем быстрее будет прогресс.
  • Моя идеальная модель состоит в том, чтобы позволить одному человеку подробно изучить технологию в каждой проблеме, а затем повторить ее для всех, подобно классу обмена, который может удвоить эффективность обучения.
  • В этой группе вам не нужно беспокоиться о собственной некомпетентности, не беспокоиться о том, что проблема слишком наивна, чтобы говорить о ней, смело высказывайте проблему и позволяйте большему количеству людей анализировать ее вместе, это не имеет значения. если ты скажешь это неправильно
  • Если вы хотите присоединиться к группе, добавьте меня в WeChat 223344386 и ответьте группе

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

Кроме того, рекомендуется обратить внимание на мой публичный аккаунт WeChat [Front-end Technology Jianghu].Помимо подробных и хороших статей, есть также [500 вопросов для фронт-энд-интервью], которые я тщательно подготовил для вам проверить.