关于useState踩过的坑

100 阅读1分钟

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);