REACT系列:2-避免 JSX 回调中的闭包陷阱

30 阅读1分钟

避免 JSX 回调中的闭包陷阱

在 React 中,闭包陷阱是常见的问题,特别是在事件处理函数、定时器和副作用中。以下是一些有效的避免方法:

1. 使用函数式更新

错误代码:

function Counter() {
  const [count, setCount] = useState(0);
  
  const handleClick = () => {
    // 闭包陷阱:count 是创建时的值
    setCount(count + 1);
  };
  
  return <button onClick={handleClick}>Count: {count}</button>;
}

解决方案:

function Counter() {
  const [count, setCount] = useState(0);
  
  const handleClick = () => {
    // 使用函数式更新,获取最新状态
    setCount(prevCount => prevCount + 1);
  };
  
  return <button onClick={handleClick}>Count: {count}</button>;
}

2. 使用 useRef 保存可变值

问题代码:

function Timer() {
  const [time, setTime] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      // 闭包陷阱:time 始终是初始值 0
      setTime(time + 1);
    }, 1000);
    
    return () => clearInterval(interval);
  }, []);
  
  return <div>Time: {time}</div>;
}

解决方案:

function Timer() {
  const [time, setTime] = useState(0);
  const timeRef = useRef(time);
  
  // 同步 ref 与 state
  useEffect(() => {
    timeRef.current = time;
  }, [time]);
  
  useEffect(() => {
    const interval = setInterval(() => {
      // 使用 ref 获取最新值
      setTime(timeRef.current + 1);
    }, 1000);
    
    return () => clearInterval(interval);
  }, []);
  
  return <div>Time: {time}</div>;
}