1. 调用 set 函数 不能改变运行中代码的状态
function handleClick() {
console.log(count); // 0
setCount(count + 1); // Request a re-render with 1
console.log(count); // Still 0!
setTimeout(() => {
console.log(count); // Also 0!
}, 5000);
}
// 更新状态不会影响已经运行的事件 如果需要使用下一个状态 可以在传递给set函数之前将它保存在一个变量中
const nextCount = count + 1;
setCount(nextCount);
console.log(count); // 0
console.log(nextCount); // 1
2. useState是同步还是异步
取决于调用方法和环境 如果在事件处理函数或者useEffect中调用,那么react会将其视为异步操作,因为react会将多个set函数调用合并为一个批处理
另外在定时器或源生事件监听器等异步代码中调用set函数,则react会立即进行状态更新,因react无法确定何时完成异步操作
import { useState, useEffect } from 'react';
function Ex(){
const [ count, setCount ] = useState(0)
useEffect(()=>{
setTimeout(()=>{
setCount(count+1)
log(count) // 输出0
},100)
}, [])
}
return (
<div>{count}</div>
)
在这个代码片段中,当组件挂载完成后,setTimeout函数将在1s后调用,更新count状态。由于react无法确定何时完成异步操作,因此将立即更新状态,输出0。
3. 解决方法
用useRef存储数据
// 封装一个useRef函数
function useLatest<T>(value: T) {
const ref = useRef(value);
ref.current = value;
return ref;
}
// 使用useLatest返回的值
const [countDownTime, setCountDownTime] = useState<number>(3);
const realTime = useLatest(countDownTime);