-
最近在自学React中,因为使用的公司内网,所以无法做笔记,那么就刚好在掘金上分享一下自己的心得,也当做笔记来使用。
-
刚开始看React中的hooks的时候,用到了useState,但是看文档的时候迷迷糊糊的,为什么state叫做照片快照,这讲的到底是啥。
-
首先这是官方的文档https://zh-hans.react.dev/learn/state-as-a-snapshot
-
看完后我依然搞不清楚,但是通过询问AI和比较简便的例子,我还是搞懂了照片快照,也搞懂了React的渲染机制。
-
首先官方给了个例子
javascript
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1)
setNumber(number + 1)
setNumber(number + 1)
}}>+3</button>
</>
)
}
- 这个例子很简单,就是当我们对按钮设置了一个点击事件,在点击的时候调用了3次setNumber(number+1),如果按照平常的逻辑来说,这时候h1标签应该返回结果是3,但是实际情况却是下图

h1标签却只显示了1,不卖关子直接说逻辑
其实照片快照就是你想象一个「点餐 - 做菜 - 上菜」的过程
-
顾客点餐(你调用
setState
)你告诉服务员(React):"我要一份宫保鸡丁!"(
setState({ dish: '宫保鸡丁' })
)。 -
厨房做菜(React 计算新 UI)
服务员把订单交给厨房(React 的渲染引擎),厨师需要时间切菜、炒菜(重新计算组件的 JSX)。
-
服务员上菜(UI 更新完成)
只有菜做好了(渲染完成),服务员才会把菜端到你桌上(DOM 更新)。
关键点:
- 你点完菜后,不能立刻吃到(
state
不会马上更新)。 - 服务员必须按流程完成做菜和上菜(React 必须完成渲染周期)。
生活化比喻
假设你在玩大富翁,要现金的方式:
直接给固定金额
- 你说:"给我 100 元!"喊3次(
setMoney(money + 100)
,setMoney(money + 100)
,setMoney(money + 100)
) - 银行每次都看你当前有 0 元,所以每次都只给 100 元。
scss
setMoney(money + 100); // 等价于 setMoney(0 + 100)
setMoney(money + 100); // 还是 setMoney(0 + 100)
setMoney(money + 100); // 仍然是 setMoney(0 + 100)
-
喊三次,最终只拿到 100 元。
-
那么同理,我们的setNumber方法也只会
scss
setNumber(number + 1); // 等价于 setNumber(0 + 1)
setNumber(number + 1); // 还是 setNumber(0 + 1)
setNumber(number + 1); // 仍然是 setNumber(0 + 1)
-
所以h1的标签为
1
。 -
那么有人就要说了,如果我要让他像我们平常那样执行3次,
h1标签
应该展示为3
要怎么做呢?
ini
setNumber(number =>number + 1);
setNumber(number =>number + 1);
setNumber(number =>number + 1);

现在再来说原理
关键区别:传递「值」vs 传递「函数」
1. 传递普通值(如 number + 1
)
-
React 行为 :直接使用当前渲染中的
number
值计算新值。 -
你的例子:
jsx
scsssetNumber(number + 1); // 等价于 setNumber(0 + 1) setNumber(number + 1); // 还是 setNumber(0 + 1) setNumber(number + 1); // 仍然是 setNumber(0 + 1)
- 结果 :三次都基于初始值
0
计算,最终只更新一次,number
变为1
。
- 结果 :三次都基于初始值
2. 传递函数(如 prev => prev + 1
)
-
React 行为:将所有更新函数按顺序排队,每个函数都基于上一次更新后的结果计算。
-
你的例子:
jsx
inisetNumber(number => number + 1); // 第一次:0 → 1 setNumber(number => number + 1); // 第二次:1 → 2 setNumber(number => number + 1); // 第三次:2 → 3
- 结果 :三次更新依次生效,
number
最终变为3
。
- 结果 :三次更新依次生效,
生活化比喻
还是你在玩大富翁,换了另外一种要现金的方式:
- 你说:"把我现在的钱加 100 给我!"(
setMoney(prev => prev + 100)
) - 银行第一次给 0+100=100 元,第二次给 100+100=200 元,第三次给 200+100=300 元。
- 喊三次,最终拿到 300 元。
总结
写法 | 计算方式 | 最终结果 |
---|---|---|
setNumber(number + 1) |
基于当前渲染的 number 值(固定值) |
只更新一次 |
setNumber(prev => prev + 1) |
基于上一次更新后的结果(动态值) | 累加多次 |
给一个我个人通俗易懂的解释:如果你不是函数的话,那么碰到修改的时候,他会把你要修改的记住,就是先不处理setNumber,而是等所有的方法执行完以后,再统一执行setNumber,如果你是函数,那么他就会依次执行。
我是罗密欧与猪过夜,感谢您的观看,有错误可以在底下评论区指正