所有的 state 都是 const
可以认为每次 Render 的内容都会形成一个快照并保留下来,因此当状态变更而 Rerender 时,就形成了 N 个 Render 状态,而每个 Render 状态都拥有自己固定不变的 Props 与 State。
<p>You clicked {count} times</p>
其中的 count 并非变量、更不是事件监听器之类的东西。每次 setState 的时候,react 直接重新渲染 DOM 树,渲染的时候给 count 赋一个常量的值。
同样的,props 也是在 render 的时候生成一个新的 const
与 state 一样,useEffect 本身不涉及事件监听
每次渲染的时候,effect 的函数对象都是不同的
不同次的 render 事件处理函数是独立的
function Counter() {
const [count, setCount] = useState(0);
function handleAlertClick() {
setTimeout(() => {
alert('You clicked on: ' + count);
}, 3000);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>add</button>
<button onClick={handleAlertClick}>show</button>
</div>
);
}
点击"add"按钮 3 次,然后点击"show",在 handleAlertClick 等待的 3s 内快速点击 add
最后 alert 的还是 3,并没有因为 count 改变了而改变
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
上面的 useEffect 在每次 Render 过程中,拿到的 count 都是固化下来的常量
并不是 count 的值在“不变”的 effect 中发生了改变,而是 effect 函数本身在每一次渲染中都不相同
第一次 render
useEffect(() => {
document.title = `You clicked ${0} times`;
});
点击后
useEffect(() => {
document.title = `You clicked ${1} times`;
});
再次点击后
useEffect(() => {
document.title = `You clicked ${2} times`;
});
同样的,组件被销毁时执行的那个消除副作用的回调函数,里面的 state 还是创建时的对象
值得一提的是,消除副作用的时机在下一次绘制 ui 之后,如原 state 为{id: 10},清除并更新 state 为{id: 20}的顺序是这样的:
如果用 id 是一个变量的想法去想,id 已经变成 20 了,怎么知道它之前是 10 呢,这是很费解的,但是以“这个 state 是上次 render 的版本”的这种思路来看,就可以理解了
有些时候,我们希望获取的是真的当前的值,那么用 ref 就好了