react hooks useState值为什么没有生效?

作者站长头像
站长
· 阅读数 7

今天在工作中遇到一个react hooks问题,虽然解决了但是对于其中的原因不太理解,这里发出来和大家一起讨论一下。具体代码如下,场景步骤如下:

  1. 点击一次,执行running后,isPolling设为true,并触发polling的useEffect
  2. 快速再点击一次,执行running,因为running前执行了cancle,所以这时候running内的isPolling应该是false,但实际还是true

看了一些批量更新的知识,好像解释不了这种现象。大家有什么看法吗?

import { useCallback, useEffect, useState } from "react";

export default function MyApp() {
  const [isPolling, setIsPolling] = useState(false);
  const [pollingCount, setPollingCount] = useState(0);
  const [timer, setTimer] = useState();

  const handleClick = () => {
    cancle();
    running();
  };

  useEffect(() => {
    if (isPolling && pollingCount <= 3) {
      console.log("33");
      clearTimeout(timer);
      setTimer(
        setTimeout(() => {
          console.log("44");
          running();
        }, 1000)
      );
    }
  }, [isPolling, pollingCount]);

  const running = useCallback(() => {
    console.log("running11:", isPolling, pollingCount);

    if (!isPolling) {
      console.log("11");
      setIsPolling(true);
    } else if (isPolling) {
      console.log("22");
      setPollingCount(pollingCount + 1);
    }
  }, [isPolling, pollingCount]);

  const cancle = () => {
    setIsPolling(false);
    setPollingCount(0);
  };

  return (
    <div>
      <div onClick={handleClick}>点击</div>
    </div>
  );
}

执行结果如下react hooks useState值为什么没有生效?

回复
1个回答
avatar
test
2024-06-25

其实这个问题很基础,甚至还不涉及到任何框架,这里我用最简单的模型来简化一下你这个问题

const [isPolling, setIsPolling] = useState(true);

const handleClick = () => {
    setIsPolling(false)
    console.log(isPolling); // true
};

isPolling是一个常量,在同一个作用域内,无论使用什么方式,都不可能实现后续去改变它的值,这就回答了你的疑问,为什么调用 setIsPolling(false) 后,isPolling的值还是 true

其实每次更新 useState 定义的状态,都会驱动 函数组件 重新执行,在重新执行的作用域中,isPolling的值才是更新后的值,

那么在更新之前的上一次作用域中如何确保拿到更新后的值呢,React也提供了相应的方式,使用 setter 的回调

setIsPolling((prevIsPolling) => {
    console.log(isPolling); // false
})

React内部会在组件对应的 fiber 结构上维护一个更新队列,对于同一个状态连续的 setState 调用会形成一个循环链表,将上一次 setState 的结果传递给下一个 setState 的回调,因此通过回调的方式你能拿到上一次 setIsPolling 的新值

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容