搞不懂 useState 为什么会这么设计?

124 天前
 dcsuibian

以下代码

import {useState} from "react";

export default function StateUpdate() {
    const [A, setA] = useState(1)
    console.log('A', 'render', A)
    return (
        <div>
            <button onClick={() => {
                setA(prev => {
                    console.log('A', 'prev1', prev)
                    return prev + 1
                })
                setA(prev => {
                    console.log('A', 'prev2', prev)
                    return prev + 1
                })
                setA(prev => {
                    console.log('A', 'prev3', prev)
                    return prev + 1
                })
                setA(prev => {
                    console.log('A', 'prev4', prev)
                    return prev + 1
                })
                console.log('A', 'state', A)
            }}>
                button A {A}
            </button>
        </div>
    )
}

点击一下按钮后的执行结果是什么?

A state 1正正好好卡在中间,虽然此时状态还是 1 。但说明了 prev1 这个函数是立即执行的。

我真的搞不懂为什么要这么设计?

4741 次点击
所在节点    React
56 条回复
3059349417
124 天前
你没学过编程么,异步不懂?
MorningStar0
124 天前
调用 prev1 的时候组件更新然后后面的 set 函数都会进入等待更新队列,这是时候执行 console 所以输出了 state 。后面的就进行合并更新了。对于合并更新参考 https://juejin.cn/post/7228851979462737978
vincenteof
124 天前
react.dev 先读一遍
dcsuibian
124 天前
@3059349417 你有看我的内容吗? prev1 这里明显是被同步的调用了(虽然状态没更新),而其他的都是异步的。
chenliangngng
124 天前
state 1 那是因为这里是个闭包,底层的 A 其实已经改了
bojackhorseman
124 天前
上面说的很清楚啦。
看过一条推文大意是很多人懂 js 所以就下意识以为也懂 React ,实际上并没有仔细看过文档。一开始写 react 我也是,结果踩了一堆坑。比如 useEffect 和我以为的 vue watch 根本不一样,还是写 vue 顺手
codehz
124 天前
除了 react 有意将副作用隔离之外还有一个就是语言限制,即你不能修改一个被解构出来的变量(虽然就算你不解构它也不会变)
dcsuibian
124 天前
@chenliangngng 我不是关心这个值,我是关心为什么这个函数是立即执行了
zackzergzeng
124 天前
要先把 react 这个概念先搞懂(范志毅脸)
Bijiabo
124 天前
1. 打开 Google
2. 找到输入框,输入“React useState 原理”
3. 按下回车
4. 阅读文章
angrylid
124 天前
这个应该是 stale closure
ivslyyy
124 天前
ivslyyy
124 天前
@dcsuibian

Here, n => n + 1 is called an updater function. When you pass it to a state setter:

React queues this function to be processed after all the other code in the event handler has run.
During the next render, React goes through the queue and gives you the final updated state.
wgbx
124 天前
setA 是函数,他映射的 useState 函数是异步函数,console.log('A', 'state', A)展示 1 ,有啥问题?
clue
124 天前
所以, 你是对时序有要求?

如果是我设计的话, 考虑有个 effect B 依赖 A, 那我修改 A 多次, 这个 effect B 是否要执行多次呢? react 重新执行 hook, 我记得是需要再次执行 render 函数的, 碰到你这个场景, 如果 setState 时正在执行 render, 要怎么处理呢?

总之这种 依赖 -> 响应 的模式很脆弱, 为了防止出问题, 会加很多限制与异步
foolnius
124 天前
dcsuibian
124 天前
@wgbx 我对他打印的值一点问题都没有,我有问题的是为什么打印的是:
A prev1 1
A state 1
A prev2 2
A prev3 3
而不是:
A state 1
A prev1 1
A prev2 2
A prev3 3
Imindzzz
124 天前
经典面试题“setState 是异步还是同步”
swaggeek
124 天前
@dcsuibian 设值这个过程是一个同步的过程吧,需要执行函数,然后拿到新值,所以立刻执行了,后面的没有立即执行,是因为像 2 楼说的,进入了批量更新的队列,被加了锁了。需要等这次更新完,才能执行,有点像微任务队列吧。
barbara012
124 天前
怎么感觉大多都没 get 到 op 困惑点?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1006034

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX