首页 > 解决方案 > 为什么 React 在 useState 中使用了错误的值?

问题描述

我有一个像这样的 React 组件:

https://codepen.io/darajava/pen/NWrdWeP?editors=0010

function TestUseState() {
  const [count, setCount] = useState(0);
  const buttonRef = useRef(null);

  useEffect(() => {
    buttonRef.current.addEventListener("click", () => {
      alert(count);
    });

    setCount(10000);
  }, []);
  
  return (
    <div ref={buttonRef}>
      Click
    </div>
  )
}

我在按钮上设置了一个事件监听器,它似乎采用了状态的初始值,之后直接设置它。这是预期的行为吗?我怎样才能避免这种情况?

有问题的实际代码(无效,仅添加了相关部分):

const Game = () => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const [player, setPlayer] = useState<IPlayer>();

  const setPosition = (newPos) => {
    console.log(player); // <--- player is undefined on mousemove
  };

  useEffect(() => {
    canvas = canvasRef.current;
    ctx = canvas.getContext('2d');
    
    canvas.addEventListener('mousemove', (e: MouseEvent) => {
      setPosition(getCursorPosition(canvas, e));
    });
  }, []);


  return (
    <canvas ref={canvasRef} styleName="canvas" />
  );
}

标签: reactjsuse-state

解决方案


是的,这是意料之中的,但我能理解为什么它看起来很奇怪。

当您在 useEffect 挂钩中添加 ref 时,您将关闭 count 的值并将其保存以备后用,因此当您单击 sub 时,它会显示组件初始化时的值。

如果你想提醒 count 的实际值可以添加onClick={()=>alert(count)}到 div 中,这也更多地遵循 React 的声明式风格。

不鼓励在 React 中使用 refs,因为 React 维护一个虚拟 dom。当您需要直接访问 dom 元素时,您可以使用 refs。

编辑:您也可以将其用于鼠标移动事件:

https://reactjs.org/docs/events.html#mouse-events

在功能组件的主体中单独编写处理函数,并将其传递给canvas元素的onMouseMoveprop。


推荐阅读