在hooks出现以前, setState是惟一的方式来改变组件的内部state. 本文梳理一下, setState的工做原理和执行流程.javascript
// componentjava
setState(nextState, callback) {
// 添加异步队列 不是每次都更新
this.$updater.addCallback(callback)
this.$updater.addState(nextState)
}
复制代码
// updaternode
getState() {
let { instance, pendingStates } = this
let { state, props } = instance
// 合并待处理状态数组
if (pendingStates.length) {
state = { ...state }
pendingStates.forEach(nextState => {
let isReplace = _.isArr(nextState)
if (isReplace) {
nextState = nextState[0]
}
if (_.isFn(nextState)) {
// 函数方式将当即执行,它能够得到以前合并的状态结果
nextState = nextState.call(instance, state, props)
}
// replace state
if (isReplace) {
state = { ...nextState }
} else {
// 合并新旧状态
state = { ...state, ...nextState }
}
})
pendingStates.length = 0
}
return state
}
复制代码
// updater
addState(nextState) {
if (nextState) {
// 放入更新队列
this.pendingStates.push(nextState)
// 若是当前队列没有工做则直接更新
if (!this.isPending) {
this.emitUpdate()
}
}
}
emitUpdate(nextProps, nextContext) {
this.nextProps = nextProps
this.nextContext = nextContext
// receive nextProps!! should update immediately
nextProps || !updateQueue.isPending
? this.updateComponent()
: updateQueue.add(this)
}
// updateQueue
add(updater) {
this.updaters.push(updater)
}
batchUpdate() {
if (this.isPending) {
return
}
this.isPending = true
let { updaters } = this
let updater
while (updater = updaters.pop()) {
updater.updateComponent()
}
this.isPending = false
}
//updater
updateComponent() {
let { instance, pendingStates, nextProps, nextContext } = this
if (nextProps || pendingStates.length > 0) {
// ...
// getState 合并全部的state的数据,一次更新
shouldUpdate(instance, nextProps, this.getState(), nextContext,
this.clearCallbacks)
}
}
function shouldUpdate(component, nextProps, nextState, nextContext, callback) {
component.forceUpdate(callback)
}
// Component
// 跳过全部生命周期执行强制更新
forceUpdate(callback) {
// 实际更新组件的函数
let { $updater, $cache, props, state, context } = this
//...
// 下面才是重点 diff
let newVnode = renderComponent(this)
let newNode = compareTwoVnodes(vnode, newVnode, node, getChildContext(this,
parentContext))
// ...
}
复制代码