-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 19 题:React setState 笔试题,下面的代码输出什么? #18
Comments
请问一下大佬,isBatchingUpdates的判断条件是什么呀? |
我理解的是:isBatchingUpdates 默认值为 false,当 react 自身的事件处理函数或 react 生命周期触发时,isBatchingUpdates 会被赋值为 true,当更新完成时又会被复原为 false。 @code-coder |
|
具体可以见 ReactFiberScheduler 中的 performWork 和 performSyncWork。 楼主说的基本是对的,如果有这种 async 的 work 就不执行 batch update 如果没有 async 的就执行 batch update,setTimeout 和 promise 这些要进入 EventLoop 队列的都会被认为是 async work。 |
哦也我做对了 |
@azl397985856 在React的setState函数实现中,会根据一个变量 isBatchingUpdate 来判断是直接同步更新this.state还是放到队列中异步更新 。React使用了事务的机制,React的每个生命周期和合成事件都处在一个大的事务当中。在事务的前置钩子中调用batchedUpdates方法修改isBatchingUpdates变量为true,在后置钩子中将变量置为false。原生绑定事件和setTimeout异步的函数没有进入到React的事务当中,或者当他们执行时,刚刚的事务已近结束了,后置钩子触发了,所以此时的setState会直接进入非批量更新模式,表现在我们看来成为了同步SetState。 |
很好理解的问题 正常情况下 react是会同步更新数据的 也就是说isBatchingUpdate触发变成true 但是 如果你将state的状态值加入到setTimeout的延迟处理队列中 打印出来的值就是setState之后的值,或者你同时调用setState的第二个参数 也会做到异步操作 获取设置之后的state value |
题目呢??? |
做成了 0022 哎。竟然有isBatchingUpdates这种东西 学习了 @yhlben 。 |
我打印的 0 0 1 1 |
react-hooks时代貌似改写了这种方式,我用react-hooks写法写出来的结果都是0 |
更新的方式没有更改,首先是因为useEffect函数只运行了一次,其次setTimeout是个闭包,访问到的值一直是0(按照正常的写法setVal(val+1))。以例子来看的话,并没有执行更新的操作。 具体可以参考 issue讨论: facebook/react#14010 |
恕我直言, 这其实就是react的bug, 整出这么大一堆概念, 就是想让你们接受这个bug, 不要踩这个坑 |
应该是setVal((val) => val+1) |
class Example extends React.Component {
constructor() {
super();
this.state = {
val: 0
};
}
componentDidMount() {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 1 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 2 次 log
setTimeout(() => {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 3 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 4 次 log
}, 0);
}
render() {
return null;
}
}; |
为什么不是 0 0 3 4 |
react的state是为view服务的,state到view是响应式的,这种代码看瞎眼 |
我刚开始得到结果也是0034,看楼主的解答,是前两次 |
react的setState可以认为是微任务的一次执行,但是我有点不太明白,setTimeout内的setState为什么没有批量更新? |
对于 非concurrent 模式 答案 0023 屏幕显示 0 1 2 3
对于 concurrent 模式 正常60hz刷新率情况下 答案 0011 屏幕显示 1 2
|
因为你开启了 concurrent 模式 见我的回复 👆 |
虽然说是批量更新,但是两者的值指向同一个元素,因此后面的覆盖前面的 |
@wangmaoshu 那你的意思是说 如果是事件,比如点击的时候结果会不一样么?我用点击事件,做这个操作和用 didmount执行,都是一样的结果 |
react v17.0.0 0 0 2 3 |
批处理机制:setstate不会立即更新state,而是将更新数据放入队列,在事件循环结束统一更新,提高效率 取决于setstate是否使用批处理机制,在事件监听函数和生命周期函数中异步更新,在setTimeout中同步更新;不是绝对固定,react会调整策略 |
现在考这题已经没有意义了。。React 18默认并发就是0011,18以下就是0023。。 |
当前线上绝大多数还是18以下吧 |
题 class Example extends React.Component {
constructor() {
super();
this.state = {
val: 0
};
}
componentDidMount() {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 1 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 2 次 log
setTimeout(() => {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 3 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 4 次 log
}, 0);
}
render() {
return null;
}
}; 答 0 // react 的可控范围内 ,批量更新 解释:#17 |
当前函数式组件当中通过useState去定义state然后通过setState的回调函数的方式+1,react |
这个在react的Concurrent mode下打印的是0,0,1,1,在Sync mode下打印的是0,0,2,3 |
1、第一次和第二次都是在 react 自身生命周期内,触发时 isBatchingUpdates 为 true,所以并不会直接执行更新 state,而是加入了 dirtyComponents,所以打印时获取的都是更新前的状态 0。
2、两次 setState 时,获取到 this.state.val 都是 0,所以执行时都是将 0 设置成 1,在 react 内部会被合并掉,只执行一次。设置完成后 state.val 值为 1。
3、setTimeout 中的代码,触发时 isBatchingUpdates 为 false,所以能够直接进行更新,所以连着输出 2,3。
输出: 0 0 2 3
The text was updated successfully, but these errors were encountered: