首頁  >  文章  >  web前端  >  React Event事件註冊的實現

React Event事件註冊的實現

不言
不言原創
2018-07-20 11:22:001556瀏覽

這篇文章要跟大家介紹的內容是關於React Event事件註冊的實現,有著一定的參考價值,有需要的朋友可以參考一下。

React 元素的事件處理和 DOM元素的很相似。但是有一點語法上的不同:

  • React事件綁定屬性的命名採用駝峰式寫法,而不是小寫。

  • 如果採用JSX 的語法你需要傳入一個函數作為事件處理函數,而不是一個字串(DOM元素的寫法)

並且React 自己內部實作了一個合成事件,使用React 的時候通常你不需要使用addEventListener 為一個已建立的DOM 元素加入監聽器。你僅僅需要在這個元素初始渲染的時候提供一個監聽器。

我們看一下這是怎麼實現的

React 事件機制分為事件註冊,和事件分發,兩個部分

事件註冊

// 事件绑定
function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
}

  return (
    <a>
      Click me
    </a>
  );

上述程式碼中,onClick 作為一個props 傳入了一個handleClick,在元件更新和掛載的時候,會對props處理, 流程如下:
React Event事件註冊的實現

#核心程式碼:
ReactDOMComponent.js 進行元件載入(mountComponent)、更新(updateComponent) 的時候,呼叫_updateDOMProperties 方法對props 進行處理:

ReactDOMComponent.js

_updateDOMProperties: function(lastProps, nextProps, transaction) {
...
if (registrationNameModules.hasOwnProperty(propKey)) {
        if (nextProp) {
          // 如果传入的是事件,去注册事件
          enqueuePutListener(this, propKey, nextProp, transaction);
        } else if (lastProp) {
          deleteListener(this, propKey);
        }
      } 
...
}

// 注册事件
function enqueuePutListener(inst, registrationName, listener, transaction) {
  var containerInfo = inst._nativeContainerInfo;
  var doc = containerInfo._ownerDocument;
    ...
    // 去doc上注册
  listenTo(registrationName, doc);
    // 事务结束之后 putListener
  transaction.getReactMountReady().enqueue(putListener, {
    inst: inst,
    registrationName: registrationName,
    listener: listener,
  });
}

看下綁定方法

ReactBrowserEventEmitter.js

listento

//registrationName:需要绑定的事件
//当前component所属的document,即事件需要绑定的位置
listenTo: function (registrationName, contentDocumentHandle) {
    var mountAt = contentDocumentHandle;
    //获取当前document上已经绑定的事件
    var isListening = getListeningForDocument(mountAt);
    ...
      if (...) {
      //冒泡处理  
      ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(...);
      } else if (...) {
        //捕捉处理
        ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(...);
      }
      ...
  },

走到最後其實就是doc.addEventLister(event, callback, false);

可以看出所有事件綁定在document上
所以事件觸發的都是ReactEventListener的dispatchEvent方法

回呼事件儲存

listenerBank

react 維護了一個listenerBank 的變數保存了所有的綁定事件的回呼。
回到之前註冊事件的方法

function enqueuePutListener(inst, registrationName, listener, transaction) {
  var containerInfo = inst._nativeContainerInfo;
  var doc = containerInfo._ownerDocument;
  if (!doc) {
    // Server rendering.
    return;
  }
  listenTo(registrationName, doc);
  transaction.getReactMountReady().enqueue(putListener, {
    inst: inst,
    registrationName: registrationName,
    listener: listener,
  });
}

當綁定完成以後會執行putListener。

var listenerBank = {};
var getDictionaryKey = function (inst) {
//inst为组建的实例化对象
//_rootNodeID为组件的唯一标识
  return '.' + inst._rootNodeID;
}
var EventPluginHub = {
//inst为组建的实例化对象
//registrationName为事件名称
//listner为我们写的回调函数,也就是列子中的this.autoFocus
  putListener: function (inst, registrationName, listener) {
    ...
    var key = getDictionaryKey(inst);
    var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {});
    bankForRegistrationName[key] = listener;
    ...
  }
}

EventPluginHub在每個React中只會實例化一次。也就是說,項目組所有事件的回呼都會儲存在唯一的listenerBank。

相關推薦:

React的使用:React元件內部的狀態管理

以上是React Event事件註冊的實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn