当前位置: 首页 > 知识库问答 >
问题:

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

能向晨
2023-10-19

今天在工作中遇到一个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>  );}

执行结果如下

共有2个答案

相温文
2023-10-19
const running = useCallback(() => {    setIsPolling((currentIsPolling) => {        console.log("running11:", currentIsPolling, pollingCount);        if (!currentIsPolling) {            console.log("11");            return true;        } else {            console.log("22");            setPollingCount(pollingCount + 1);            return currentIsPolling; // return current value without change        }    });}, [pollingCount]);
潘雅珺
2023-10-19

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

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 的新值

 类似资料:
  • 问题内容: 为什么不自动生成?我在应用程序服务器上遇到了一个问题,该服务器显然正在缓存一个旧类。 问题答案: 不会自动生成serialversionuid,因为它很危险。设置serialversionuid时,表示类的两个版本在序列化方面兼容。 假设您有一个名为Foo的类,并且它 没有serialversionuid (默认值),并且将Foo的实例序列化为文件。稍后,您将一些新成员添加到Foo类。

  • 问题内容: 我正在尝试做这样的事情: 不幸的是,即使在Java 9中也不存在。 为什么它被遗漏了? 建议的解决方法是什么? 问题答案: 为什么它被遗漏了? 该API提供了可重用的构建块。这里的相关积木是,,。通过这些,您可以实现所需的功能:将流内映射到对象,然后获得平面图。提供构建基块的排列是不切实际的,并且很难扩展。 建议的解决方法是什么? 如前所述,使用可用的构建基块(+ ):

  • 许多编译器都提供128位整数类型,但我使用过的编译器都没有提供typedefs。为什么? 据我回忆,标准 用于此目的的储量 鼓励提供此类类型的实现提供typedef 要求此类实现提供至少128位的intmax_t (而且,我不相信我使用了实际上符合最后一点的实现)

  • 直截了当的问题是,似乎无法在用户完成表单后指向的视图中显示我的viewBag值。 请指教...谢谢 我的索引操作结果简单返回模型数据。 my Get Edit”action result,只是使用相同的模型数据作为索引。 My Post"Edit"ActionResult,将新值(如果有)分配给模型并重定向到Index页面,但Index页面不显示ViewBag值?? 在我的索引视图中。。。

  • 父组件相关代码 html js 子组件 复现步骤: 第一次打开弹框: 时间选择器显示的是当前时间 更改时间选择器的时间之后关闭弹框 第二次打开弹框,显示时间是之前弹框里面时间选择的时间,而不是当前时间?

  • 我正在与Kotlin研究地图,并决定运行以下代码: 这让我: 我以为的冲突导致了一个列表。然后当我尝试这是静态编程语言的时,我也没有得到任何冲突。 问题: 我在这个简单的碰撞示例中错过了什么? 每个实现最常见的冲突行为是什么?