在上一节的基础上修改代码。
前置知识:
react基础篇第五点:https://www.yuque.com/linhe-8mnf5/fxyxkm/tnkpyg#jBiGv
原理篇:https://www.yuque.com/linhe-8mnf5/fxyxkm/daa695
- 在react中事件是异步的,事件更新是批量的。
- 调用setState并没有立马更新,而是先缓存起来,等事件函数完成后在进行批量更新,一次更新并重新渲染。
1、改造index.js,先手动实现批量更新
// index.jshandleClick = () => {updateQueue.isBatchingUpdate = truethis.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)updateQueue.batchUpdate()}
2、改造Component.js
// Component.jsimport { createDom } from './react-dom'// 更新队列export const updateQueue = {isBatchingUpdate: false, // 当前是否处于批量更新模式,默认值falseupdaters: new Set(), // 传入的setState集合// 批量更新方法batchUpdate() {for (let updater of this.updaters) {updater.updateClassComponent()}this.isBatchingUpdate = false}}class Updater {constructor(classInstance) {this.classInstance = classInstance // 类组件实例this.penddingStates = [] // 等待生效的状态this.callbacks = []}addState(partialState, callback) {this.penddingStates.push(partialState) // 等待生效的状态if (typeof callback === 'function') {this.callbacks.push(callback) // 更新后的回调}// 如果当前是批量更新模式,先缓存if (updateQueue.isBatchingUpdate) {updateQueue.updaters.add(this)} else {// 直接更新组件this.updateClassComponent()}}updateClassComponent() {const { penddingStates, classInstance, callbacks } = this// 说明有setStateif (penddingStates.length > 0) {classInstance.state = this.getState() // 计算新状态// 更新domclassInstance.forceUpdate()// 调用setState回调callbacks.forEach(callback => callback())// 清空callbackcallbacks.length = 0}}getState() {let { penddingStates, classInstance } = thislet { state } = classInstance// 老状态新状态合并penddingStates.forEach(nextState => {// setState传值为函数,要传入老状态,返回新状态,在进行合并if (typeof nextState === 'function') {nextState = nextState(false)}// 合并状态,新状态覆盖老状态state = { ...state, ...nextState }})// 清空等待生效的状态penddingStates.length = 0return state}}// 被继承的父类Componentclass Component {static isReactComponent = trueconstructor(props) {this.props = propsthis.state = {}this.Updater = new Updater(this)}// 被调用的this.setState()方法setState(partialState, callback) {this.Updater.addState(partialState, callback)}forceUpdate() {let newVdom = this.render() //获取新domupdateClassComponent(this, newVdom) // 更新}}// 更新类组件function updateClassComponent(classInstance, newVdom) {const oldDom = classInstance.dom // 取出类组件上次渲染出来的真实dom// 创建新的DOMconst newDom = createDom(newVdom)// 新的替换老的oldDom.parentNode.replaceChild(newDom, oldDom)classInstance.dom = newDom}export default Component
3、实现效果

4、源代码
本文地址:https://gitee.com/linhexs/react-write/tree/4.update-queue/
