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

React钩子:新状态值未反映在setInterval回调中

段溪叠
2023-03-14

我有一个函数反应组件,它有一个从10000开始到0的计数器。

我正在组件安装期间使用useEffect挂钩设置setInterval回调。然后,回调更新计数器状态。

但是不知道为什么,计数值从来没有减少过。每次回调运行时,计数为10000。

(我正在使用react

功能组件如下所示:

import React, { useState, useEffect, useRef } from 'react'

const Counter = () => {
  const timerID = useRef()
  let [count, setCount] = useState(10000)

  useEffect(() => {
    timerID.current = setInterval(() => {
      //count here is always 10000
      if (count - 1 < 0) {
        setCount(0)
      } else {
        setCount(count - 1)
      }
    }, 1)
  }, [])

  return <h1 className="counter">{count}</h1>
}

export default Counter

这里是codesandbox的链接:链接

共有3个答案

翁良弼
2023-03-14

正如您所说,当组件装入时,您正在声明effect函数。所以在范围内,时间值存储的内部计数等于10000。这意味着每次间隔函数执行时,它都从闭包(10000)中获取计数值。实际上,要正确地做这件事是相当困难的。丹写了关于它的全部博客文章

汝承载
2023-03-14

有两种选择:

1) 在依赖项中包括count

这并不理想,因为这意味着每次更改计数时都会创建一个新的setInterval,因此您需要在每次渲染时清理它,例如:

  useEffect(() => {
    timerID.current = setInterval(() => {
      //count here is always 10000
      if (count - 1 < 0) {
        setCount(0)
      } else {
        setCount(count - 1)
      }
    }, 1)
    return () => clearInterval(timerID.current) // Added this line
  }, [count]) // Added count here

2)在setInterval回调函数中添加count

这是间隔的最佳方法,因为它避免了一直设置新的间隔。

 useEffect(() => {
    timerID.current = setInterval(() => {
      // count is used inside the setCount callback and has latest value
      setCount(count => {
        if (count - 1 < 0) { // Logic moved inside the function, so no dependencies
          if (timerID.current) clearInterval(timerID.current)
          return 0
        }
        return count - 1
      })
    }, 1)
    return () => {
      if (timerID.current) clearInterval(timerID.current) // Makes sure that the interval is cleared on change or unmount
    }
  }, [])

这是沙盒链接

高宸
2023-03-14

您需要监视计数中的更改,并清理useffect()

useEffect(() => {
    timerID.current = setInterval(() => {
      if (count - 1 < 0) {
        setCount(0)
      } else {
        setCount(count - 1)
      }
    }, 100)

    return () => clearInterval(timerID.current);
  }, [count])

正如@Pavel提到的,Dan Abramov在这里解释了原因。

 类似资料:
  • 问题内容: 我正在尝试新的React Hooks,并有一个带有计数器的Clock组件,该计数器应该每秒增加一次。但是,该值不会增加到超过一。 问题答案: 原因是传递给的闭包中的回调仅访问第一个渲染器中的变量,而无法访问后续渲染器中的新值,因为第二次未调用。 回调中的值始终为0 。 就像您熟悉的状态挂钩一样,状态挂钩有两种形式:一种是处于更新状态的状态,另一种是将当前状态传入的回调形式。您应该使用第

  • 我正在试用新的反应挂钩,并有一个时钟组件,计数器应该每秒钟增加一次。但是,该值不增加超过1。

  • 我正在尝试使用状态将一个表单输入值复制到另一个表单输入值,但状态没有更新 我创建了一个带有按钮的表单,其中左侧表单输入的值应复制到右侧表单输入。这是我的代码: 无论我做什么,dbSecName的状态都不会改变。我试着设置一个新的常量。我尝试使onclick函数异步并等待。如果我为我试图设置的变量的值添加,我可以正确地看到它,但是dbSecName的console.log总是显示原始值。 我真的不知

  • 我正在React中使用useState钩子,状态将不会在

  • 我没有在FabricJS事件中获得更新的状态值,如object:modified、mouse:up等。。。但我可以在回调函数中设置状态值。 当我试图获取状态值时,它返回的是初始值,而不是更新后的值。 例子: 初始值为0。我使用setCount将值更新为1。每当我试图在回调函数中获取“count”时,它都返回0或初始值。 编辑: 我试图实现的是,每当对象修改(对于撤销,重做操作)时,我试图保存Fab

  • 我正在尝试新的hooks功能,并坚持认为我的状态没有更新。 实际上,状态已更新(我可以在console.log中看到更新的值,并且我的组件会重新运行useEffect),但是useEffect方法使用我的旧状态,并仅将签名保存给第一个用户,而活动用户在状态中确实发生了更改。 我想过添加useCallback,并将我的方法移动到use效果或组件本身,但我可以设法让它工作。 状态: 这是我的效果: 这