上一篇文章中,批量更新采用的是手动控制的方式。但是我们实际的开发中,react并没有让用户手动控制批量更新,所以本节目标实现一个自动的批量更新。
1、修改index.js代码
修改前:
修改后:
// index.js
handleClick = () => {
this.setState({
number: this.state.number + 1
},() => {
console.log(`111`, this.state.number)
})
console.log(this.state.number)
this.setState({
number: this.state.number + 1
})
console.log(this.state.number)
setTimeout(() => {
this.setState({
number: this.state.number + 1
})
console.log(this.state.number)
}, 0)
}
2、合成事件
react事件采用的合成事件,并不是原生的事件。
前置知识:https://www.yuque.com/linhe-8mnf5/fxyxkm/tnkpyg#k2Xds 第二点事件
2.1 修改react-dom.js
修改react-dom.js文件的updateProps方法。之前是直接copy属性绑定到真实dom,现在绑定合成事件到真实dom。
2.2 event.js编写
// event.js
import { updateQueue } from "./Component";
/**
* 给真实dom添加事件处理函数
* 合成事件的作用:
* 1.可以做兼容处理(不同浏览器的event是不一样的);
* 2.可以在自己写的处理函数之前和之后做一些事情,比如 updateQueue.isBatchingUpdate = true 之后 updateQueue.batchUpdate()
* @param {*} dom 真实dom
* @param {*} eventType 事件类型
* @param {*} listener 监听函数
*/
export function addEvent(dom, eventType, listener) {
let store = dom.store || (dom.store = {})
store[eventType] = listener //store.onclick = handleClick
if (!document[eventType]) {
// 事件委托,统一代理到document上
document[eventType] = dispatchEvent
}
}
let syntheticEvent = {}
function dispatchEvent(event) {
let { target, type } = event //事件源:dom元素 、type:type=click
const eventType = `on${type}` // onclick
// 设置批量更新
updateQueue.isBatchingUpdate = true
// 拷贝元素事件到合成事件
createSyntheticEvent(event)
// 向上冒泡
while(target){
const { store } = target
const listener = store && store[eventType]
// 事件处理
listener && listener.call(target, syntheticEvent)
target = target.parentNode
}
// 清理event
for(let key in syntheticEvent){
syntheticEvent[key] = null
}
// 批量更新
updateQueue.batchUpdate()
}
// 拷贝原生事件到合成事件
function createSyntheticEvent(nativeEvent) {
for(let key in nativeEvent){
syntheticEvent[key] = nativeEvent[key]
}
}
需要注意向上冒泡的处理逻辑:
<button onClick={handleClick}></button>
// 如果不处理合成事件的冒泡,此处不起作用
<button>
<span onClick={handleClick}></span>
</button>
3、实现效果
4、源代码
本文地址:https://gitee.com/linhexs/react-write/tree/5.synthetic-event/