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