【React深切】React事宜机制

关于React事宜的疑问

  • 1.为何要手动绑定this
  • 2.React事宜和原生事宜有什么区别
  • 3.React事宜和原生事宜的实行递次,能够混用吗
  • 4.React事宜怎样处置惩罚跨浏览器兼容
  • 5.什么是合成事宜

下面是我浏览过源码后,将一切的实行流程总结出来的流程图,不会贴代码,假如你想浏览代码看看详细是怎样完成的,能够依据流程图去源码里寻觅。

事宜注册

《【React深切】React事宜机制》

  • 组件装载 / 更新。
  • 经由历程lastPropsnextProps推断是不是新增、删除事宜离别挪用事宜注册、卸载要领。
  • 挪用EventPluginHubenqueuePutListener举行事宜存储
  • 猎取document对象。
  • 依据事宜称号(如onClickonCaptureClick)推断是举行冒泡照样捕捉。
  • 推断是不是存在addEventListener要领,不然运用attachEvent(兼容IE)。
  • document注册原生事宜回调为dispatchEvent(一致的事宜分发机制)。

事宜存储

《【React深切】React事宜机制》

  • EventPluginHub担任治理React合成事宜的callback,它将callback存储在listenerBank中,别的还存储了担任合成事宜的Plugin
  • EventPluginHubputListener要领是向存储容器中增添一个listener。
  • 猎取绑定事宜的元素的唯一标识key
  • callback依据事宜范例,元素的唯一标识key存储在listenerBank中。
  • listenerBank的组织是:listenerBank[registrationName][key]

比方:

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

事宜触发 / 实行

《【React深切】React事宜机制》

这里的事宜实行利用了React的批处置惩罚机制,在前一篇的【React深切】setState实行机制中已剖析过,这里不再多加剖析。

  • 触发document注册原生事宜的回调dispatchEvent
  • 猎取到触发这个事宜最深一级的元素

比方下面的代码:首先会猎取到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自身完成的冒泡机制。

合成事宜

《【React深切】React事宜机制》

  • 挪用EventPluginHubextractEvents要领。
  • 轮回一切范例的EventPlugin(用来处置惩罚差别事宜的东西要领)。
  • 在每一个EventPlugin中依据差别的事宜范例,返回差别的事宜池。
  • 在事宜池中掏出合成事宜,假如事宜池是空的,那末建立一个新的。
  • 依据元素nodeid(唯一标识key)和事宜范例从listenerBink中掏出回调函数
  • 返回带有合成事宜参数的回调函数

总流程

将上面的四个流程串连起来。

《【React深切】React事宜机制》

为何要手动绑定this

经由历程事宜触发历程的剖析,dispatchEvent挪用了invokeGuardedCallback要领。

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

可见,回调函数是直接挪用挪用的,并没有指定挪用的组件,所以不举行手动绑定的状况下直接猎取到的thisundefined

这里能够运用实验性的属性初始化语法 ,也就是直接在组件声明箭头函数。箭头函数不会建立自身的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深切】React事宜机制》

由上面的流程我们能够明白:

  • react的一切事宜都挂载在document
  • 当实在dom触发后冒泡到document后才会对react事宜举行处置惩罚
  • 所以原生的事宜会先实行
  • 然后实行react合成事宜
  • 末了实行真正在document上挂载的事宜

react事宜和原生事宜能够混用吗?

react事宜和原生事宜最好不要混用。

原生事宜中假如实行了stopPropagation要领,则会致使其他react事宜失效。由于一切元素的事宜将没法冒泡到document上。

由上面的实行机制不难得出,一切的react事宜都将没法被注册。

合成事宜、浏览器兼容

  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采纳了事宜池,如许做能够大大节约内存,而不会频仍的建立和烧毁事宜对象。

别的,不论在什么浏览器环境下,浏览器会将该事宜范例一致建立为合成事宜,从而达到了浏览器兼容的目标。

引荐浏览

【React深切】setState的实行机制

    原文作者:ConardLi
    原文地址: https://segmentfault.com/a/1190000018391074
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞