1 )概述
requestWork
在中间, 会判断一个 isBatchingUpdates 做一些特定的操作2 )示例
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './demos/batchedUpdates'
ReactDOM.render(<App />, document.getElementById('root'))
demos/batchedUpdates
import React from 'react'
import { unstable_batchedUpdates as batchedUpdates } from 'react-dom'
export default class BatchedDemo extends React.Component {
state = {
number: 0,
}
handleClick = () => {
// 第一种场景 事件处理函数自带`batchedUpdates`
// this.countNumber()
// 第二种场景,主动`batchedUpdates`
// setTimeout(() => {
// this.countNumber()
// }, 0)
// 第三种场景,setTimeout中没有`batchedUpdates`
setTimeout(() => {
batchedUpdates(() => this.countNumber())
}, 0)
}
countNumber() {
const num = this.state.number
this.setState({
number: num + 1,
})
console.log(this.state.number)
this.setState({
number: num + 2,
})
console.log(this.state.number)
this.setState({
number: num + 3,
})
console.log(this.state.number)
}
render() {
return <button onClick={this.handleClick}>Num: {this.state.number}</button>
}
}
countNumber
中定义了更改 state的方法handleClick
countNumber
时,页面显示 3,但是 console 面板分别输出 3次0countNumber
countNumber
3 ) 源码
进入到 requestWork 函数中的相关判断,可以在源码 nodemodules/react-dom/cjs/react-dom-development.js 中
找到 requestWork 进行debugger,重启 react项目,之后在 Chrome 中调试
if (isBatchingUpdates) {
// Flush work at the end of the batch.
if (isUnbatchingUpdates) {
// ...unless we're inside unbatchedUpdates, in which case we should
// flush it now.
nextFlushedRoot = root;
nextFlushedExpirationTime = Sync;
performWorkOnRoot(root, Sync, true);
}
return;
}
第一种场景下
isBatchingUpdates
是 true, isUnbatchingUpdates
是 falseperformSyncWork
来帮助我们完成任务调度的过程,而非通过 requestWork
来完成的任务调度第二种场景下
countNumber
就没有 isBatchingUpdates
为 true 的情况了,就不会批量执行第三种场景下
batchedUpdates
的 API 调用 countNumber
batchedUpdates
或 interactiveUpdates
帮助我们设置上下文在 ReactFiberSchduler.js 中的 batchedUpdates
中
// TODO: Batching should be implemented at the renderer level, not inside
// the reconciler.
function batchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
const previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return fn(a);
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
}
}
}
isBatchingUpdates = true;
,在设置之前记录前值 const previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates
成之前的值 previousIsBatchingUpdates
!isBatchingUpdates && !isRendering
符合了,则调用 performSyncWork
方法同样,unbatchedUpdates
也是来自这个文件
// TODO: Batching should be implemented at the renderer level, not inside
// the reconciler.
function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
if (isBatchingUpdates && !isUnbatchingUpdates) {
isUnbatchingUpdates = true;
try {
return fn(a);
} finally {
isUnbatchingUpdates = false;
}
}
return fn(a);
}
isUnbatchingUpdates
为 truesetState
这个方法是同步的,