React Hook 中使用 setInterval() 的 Javascript 闭包

2023-12-11

在下面的示例中,我预计控制台中的计数值将像 UI 中一样增加。然而事实并非如此,该值始终为0,但UI中的值却增加了。我知道这个问题可能与 Javascript Closure 有关。在我的理解中,count应参考中的值useState。自从count更新者:setCount,价值不断增加。但是,为什么它在日志中没有增加呢? 演示:https://codesandbox.io/s/gallant-fermat-42lxq?file=/src/App.js

export default function App() {
  const [count, setCount] = useState(0);

  function innerFunction() {
    return () => {
      console.log("count: ", count);
      setCount(c => c + 1);
    };
  }

  useEffect(() => {
    const id = setInterval(innerFunction(), 1000);
    return () => clearInterval(id);
  }, []);
  return <h1>{count}</h1>;
}

问题是在 setInterval 回调中,count 的值没有改变,因为我们创建了一个闭包,其中 count 的值设置为 0,就像效果回调运行时一样

第一次渲染时,闭包 log() 将 count 变量捕获为 0。之后,即使 count 增加,log() 仍然使用初始渲染时的 count 为 0。 log() 是一个过时的闭包。

解决方案是让useEffect()知道闭包log()依赖于count并正确处理interval的重置:

在 useEffect 中添加 count 作为依赖项

useEffect(() => {
    const id = setInterval(innerFunction(), 1000);
    return () => clearInterval(id);
  }, [count]);

正确设置依赖项后,一旦计数发生变化,useEffect() 就会更新闭包。

解释

在没有依赖关系的情况下, useEffect() 仅在最初被调用。它不会被重新调用。

 useEffect(() => {
    console.log("is re-rendering");
    const id = setInterval(innerFunction(), 1000);
    return () => clearInterval(id);
  }, []);

Here, "正在重新渲染" 只记录一次。

如果您使用此语法而不是函数语法(获取最新计数状态)来设置状态。它还将行为显示为过时关闭的日志

setCount( count + 1); //always 1 as it gets 0 as count value

Since 使用效果之后没有被调用count更改时,它们采用相同的初始输入并给出相同的初始输出,因为它们不知道更改。

如果我们添加 count 作为依赖项 then 使用效果每当count值的变化和设置时间间隔也使用新的更新输入重新初始化。

更多信息

https://dmitripavlutin.com/react-hooks-stale-closures/

https://reactjs.org/docs/hooks-faq.html#what-c​​an-i-do-if-my-effect-dependency-change-too-often

Example

我已经用简单的例子展示了类似的问题。

在这里,我改变了outerVar的值(让我们认为它就像一个count状态)在第一次调用outerfn之后。

但其更新的变化并未体现出来。这就是闭包的工作原理。

let outerVar='initial-outer'
function outerfn(outerVar){
  return function innerfn(innerVar){
     console.log('outer variable: '+ outerVar)
     console.log('inner variable: '+ innerVar)
     }
 }
 
 let newfn=outerfn(outerVar)
 outerVar="updated-outer" // outerVal is now changed
 newfn('inside') // but initial outerVal is printed here

 newfn=outerfn(outerVar)//resetting closure with updated value (like adding dependency to useEffect)
 newfn('inside') // updated outerVal is printed now
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React Hook 中使用 setInterval() 的 Javascript 闭包 的相关文章

随机推荐

  • 通过 ODBC 从 C# 读取 Netezza 数据库表在 Windows 7 中不起作用

    为什么 NET 无法通过已安装的 NetezzaSQL 驱动程序连接到我的 Netezza 盒子 64 位应用程序也无法通过此 ODBC 连接进行连接 为什么会这样呢 我已在控制面板中构建了用户和系统 Netezza ODBC 连接 当我单
  • 在unix中如何删除文件的最后一个字符?

    假设我有一些任意的多行文本文件 sometext moretext lastline 如何仅删除文件的最后一个字符 e 而不是换行符或空 而不使文本文件无效 更简单的方法 输出到标准输出 不更新输入文件 sed s somefile 是一个
  • 制作模态 JInternalFrame

    我需要从 MDI JFrame 中的用户获取大量数据 文件选择 文本 日期 我需要的输入表格是JInternalFrame是模态的 我怎样才能做一个JInternalFrame modal 根据我的经验 我从来没有成功过JInternalF
  • 如何从 QListWidgetItem 获取小部件

    我制造了一个QListWidget In QLisitWidgetItems 我添加了一个QVBoxLayout That QVBoxLayout包含三个QLabels 如何获取里面的值QLabel点击时QListWidgetItem 创建
  • 有可用的 Linux RDAP 客户端吗? [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我四处寻找 认为这里可能是最快的 我在哪里可以得到任何RDAP客户端 它实际上被任何人使用吗 您可以使用用 Perl 编写的 rdapper git clone https gi
  • Kurento Media WebRTC 转 RTP

    我正在使用 kurento 的主 git 来制作 WebRTC 到 RTP 的桥接器 MediaPipeline pipeline kurento createMediaPipeline WebRtcEndpoint webRtcEndpo
  • Javascript 书签在 Firefox 中输出“true”而不是执行脚本

    我们正在运行一个快速的 JavaScript 函数来填写和保存表单 以便在工作流程中快速前进 用于测试目的 它在除 Firefox 之外的所有浏览器中运行良好 并且仅在少数人的计算机上运行 javascript function ruleD
  • 如何在 SQL Developer 中输入多值参数的绑定

    我有很多带有命名参数的 SQL 我需要能够在 SQL Developer 中执行它们 对于参数为标量值的 SQL 可以轻松地将 SQL 粘贴到工作表中 并且 SQL Developer 将提示我 在标题为 Enter Binds 的对话框中
  • Azure 构建上的 JavaScript 堆内存不足

    我将 aspnetboilerplate 与 Angular 和 NET Core 一起使用 当我尝试在 Azure 上部署应用程序时 它显示 致命错误 接近堆限制的无效标记压缩分配失败 JavaScript 堆内存不足 这是我的天蓝色管道
  • 如何在 Yii2 中的 $content 之前在主布局页面中传递全局变量

    我正在尝试使用 Nav widget 在 yii2 中创建动态菜单 这是我在主布局页面的菜单部分中的代码 echo Nav widget options gt class gt navbar nav navbar right items g
  • java.lang.IllegalStateException:在 JSF 2 中已为此响应调用 getOutputStream()

    我有一个用 xml 编写 jsp 页面的遗留代码 我正在尝试将其转换为 JSF 2 但我收到以下异常 Jul 10 2012 11 34 57 AM com sun faces application view FaceletViewHan
  • JS Canvas:如何使矩形到达边界后来回移动

    所以我有一个向右移动的矩形 我怎样才能让矩形在触及边界时反转它 我正在努力让它来回
  • CLI 中的 JUnit 测试等效项

    我编写了某些代码 但它并没有主要方法 但我想知道代码是否有问题 基本上我可以使用 Eclipse 中的 JUnit 测试用例来完成它 我使用的是 Linux 但我面临的情况是 我必须在目前没有 Eclipse 的 Windows 中测试它
  • 在 SQL 数据库上强制执行“零或一对一”关系?

    我有一个Post实体和一个FbPost entity Post FbPost为 null 或FbPost 并且没有两个Post实体可以引用相同的FbPost实体 换句话说 zero or one to one 强制执行此操作的正确方法是什么
  • 按分隔符分割字符串,但如果它被转义则不会

    如何用分隔符分割字符串 但如果它被转义则不能分割 例如 我有一个字符串 1 2 2 3 4 4 分隔符是 转义分隔符是 此外 我想忽略转义的反斜杠 所以在 the 仍然是一个分隔符 因此 使用上面的字符串 结果应该是 0 gt 1 1 gt
  • parsedhtml 不再响应

    因此 我尝试从网站获取一些文本 一旦我尝试使用 ParsedHtml 返回对象 powershell 就会停止响应 即使我让它在后台运行几分钟 它也不会再执行任何操作 造成这种情况的原因是什么 PS P gt url mywebsite P
  • Flask:当 flash() 位于 @app.before_request 中时获取随机重复的 flash 消息

    当我在 app before request 中使用 flash 时 我得到的似乎是随机数量的重复条目 一遍又一遍地刷新页面会给我 1 到 4 条重复的消息 没有任何重定向 我的代码很简单 if app config INSTANCE DE
  • 避免 html 模板中的自动转义

    尝试使用 URL 呈现 HTML 模板 问题是 URL 中包含 而这些字符被转义了 我尝试使用template URL http myurl com data aaa jpg 并且template HTML http myurl com d
  • 从 numpy 数组中分离出最大/最小的标记补丁

    我有一个大的 numpy 数组 并用 scipy 中的连接组件标签对其进行标记 现在我想创建这个数组的子集 其中只留下尺寸最大或最小的标签 当然 这两个极值都可能出现多次 import numpy from scipy import ndi
  • React Hook 中使用 setInterval() 的 Javascript 闭包

    在下面的示例中 我预计控制台中的计数值将像 UI 中一样增加 然而事实并非如此 该值始终为0 但UI中的值却增加了 我知道这个问题可能与 Javascript Closure 有关 在我的理解中 count应参考中的值useState 自从