上一篇文章中,批量更新采用的是手动控制的方式。但是我们实际的开发中,react并没有让用户手动控制批量更新,所以本节目标实现一个自动的批量更新。

1、修改index.js代码

修改前:
image.png

修改后:

  1. // index.js
  2. handleClick = () => {
  3. this.setState({
  4. number: this.state.number + 1
  5. },() => {
  6. console.log(`111`, this.state.number)
  7. })
  8. console.log(this.state.number)
  9. this.setState({
  10. number: this.state.number + 1
  11. })
  12. console.log(this.state.number)
  13. setTimeout(() => {
  14. this.setState({
  15. number: this.state.number + 1
  16. })
  17. console.log(this.state.number)
  18. }, 0)
  19. }

2、合成事件

react事件采用的合成事件,并不是原生的事件。

前置知识:https://www.yuque.com/linhe-8mnf5/fxyxkm/tnkpyg#k2Xds 第二点事件

2.1 修改react-dom.js

修改react-dom.js文件的updateProps方法。之前是直接copy属性绑定到真实dom,现在绑定合成事件到真实dom。
image.png
image.png

2.2 event.js编写

  1. // event.js
  2. import { updateQueue } from "./Component";
  3. /**
  4. * 给真实dom添加事件处理函数
  5. * 合成事件的作用:
  6. * 1.可以做兼容处理(不同浏览器的event是不一样的);
  7. * 2.可以在自己写的处理函数之前和之后做一些事情,比如 updateQueue.isBatchingUpdate = true 之后 updateQueue.batchUpdate()
  8. * @param {*} dom 真实dom
  9. * @param {*} eventType 事件类型
  10. * @param {*} listener 监听函数
  11. */
  12. export function addEvent(dom, eventType, listener) {
  13. let store = dom.store || (dom.store = {})
  14. store[eventType] = listener //store.onclick = handleClick
  15. if (!document[eventType]) {
  16. // 事件委托,统一代理到document上
  17. document[eventType] = dispatchEvent
  18. }
  19. }
  20. let syntheticEvent = {}
  21. function dispatchEvent(event) {
  22. let { target, type } = event //事件源:dom元素 、type:type=click
  23. const eventType = `on${type}` // onclick
  24. // 设置批量更新
  25. updateQueue.isBatchingUpdate = true
  26. // 拷贝元素事件到合成事件
  27. createSyntheticEvent(event)
  28. // 向上冒泡
  29. while(target){
  30. const { store } = target
  31. const listener = store && store[eventType]
  32. // 事件处理
  33. listener && listener.call(target, syntheticEvent)
  34. target = target.parentNode
  35. }
  36. // 清理event
  37. for(let key in syntheticEvent){
  38. syntheticEvent[key] = null
  39. }
  40. // 批量更新
  41. updateQueue.batchUpdate()
  42. }
  43. // 拷贝原生事件到合成事件
  44. function createSyntheticEvent(nativeEvent) {
  45. for(let key in nativeEvent){
  46. syntheticEvent[key] = nativeEvent[key]
  47. }
  48. }

需要注意向上冒泡的处理逻辑:

  1. <button onClick={handleClick}></button>
  2. // 如果不处理合成事件的冒泡,此处不起作用
  3. <button>
  4. <span onClick={handleClick}></span>
  5. </button>

3、实现效果

image.png

4、源代码

本文地址:https://gitee.com/linhexs/react-write/tree/5.synthetic-event/