【问题标题】:How to increment a state variable every second in React如何在 React 中每秒增加一个状态变量
【发布时间】:2021-12-19 23:09:56
【问题描述】:

我的代码中有一个名为“url”的组件的图像列表。我还有一个名为currImageIndex 的状态变量。我想要发生的是每次渲染这个组件时,我想启动一个计时器。该计时器运行的每一秒,我都想增加我的状态变量currImageIndex。当currImageIndex + 1 大于或等于url 长度时,我想将currImageIndex 重置为零。总体目标是通过返回<img src={url[currImageIndex]}> 来模拟图像的自动幻灯片。但是,我在增加状态变量时遇到问题。我遵循了一些我在这里找到的代码,但我不知道如何让增量工作。这是我的代码。

const { url } = props;
  const [currImageIndex, setCurrImageIndex] = useState(0);
  console.log(url)
  const increment = () => {
    console.log(url.length)
    console.log(currImageIndex)
    if (currImageIndex + 1 < url.length) {
      setCurrImageIndex((oldCount) => oldCount + 1)
    }
    else {
      setCurrImageIndex(0)
    }
  }
  useEffect(() => {
    const id = setInterval(increment, 1000);

    return () => clearInterval(id);
  }, []);

  return (
    <div className={styles.container}>
      <div className={styles.header}>Preview of GIF:</div>
      <img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
      <div>{currImageIndex}</div>
    </div>
  );

当我使用大小为 2 的 url 运行此程序时,倒数第三行 ("{currImageIndex}") 显示 1,然后是 2,然后是 3,依此类推。它永远不会重置。我的console.log(url.length) 打印 2,我的 console.log(currImageIndex) 打印 0。我想要发生的是 currImageIndex 应该是 0、1、0、1、0、1,.... 谁能帮我理解我在做什么错误的?谢谢!

【问题讨论】:

    标签: javascript reactjs react-hooks use-effect use-state


    【解决方案1】:

    原因是 setInterval 上传递的回调仅在第一次渲染时访问 currImageIndex 变量,而不是在渲染时访问新值,因此您将始终获得 currImageIndex = 0 并传递条件 if (currImageIndex + 1 &lt; url.length)。我更新了你的代码,让它像你期望的那样工作:https://stackblitz.com/edit/react-y6fqwt

    【讨论】:

      【解决方案2】:

      问题

      这里的问题是,当在间隔计时器中设置 increment 回调时,初始渲染中的 currImageIndex 状态值已过时。您正确地使用了函数状态来增加 currImageIndex 值,但 increment 函数体中的 currImageIndex 值始终是初始状态值 0 的值。

      解决方案

      这里的一个常见解决方案是使用 React ref 来缓存 currImageIndex 状态,以便可以在回调中访问当前值。

      例子:

      const [currImageIndex, setCurrImageIndex] = useState(0);
      const currentImageIndexRef = useRef();
      
      useEffect(() => {
        // cache the current state value
        currentImageIndexRef.current = currentImageIndex;
      }, [currImageIndex]);
      
      const increment = () => {
        // access the current state value
        if (currentImageIndexRef.current + 1 < url.length) {
          setCurrImageIndex((oldCount) => oldCount + 1)
        }
        else {
          setCurrImageIndex(0)
        }
      }
      
      useEffect(() => {
        const id = setInterval(increment, 1000);
        return () => clearInterval(id);
      }, []);
      

      一个更简单的解决方案是只访问在组件范围内使用状态更新程序回调关闭的url 值。使用三元运算符检查当前值加 1 是否仍小于 url 长度和状态 + 1,否则通过返回 0 重置。但是请注意,如果 url 数组是动态的,并且长度发生变化,此解决方案会因同样的原因而中断,则初始渲染中的 url 值在范围内是封闭的。

      const increment = () => {
        setCurrImageIndex((count) => count + 1 < url.length ? count + 1 : 0);
      }
      

      而 IMO 最简单的解决方案是始终增加 currImageIndex 状态并采用 url 长度的模数来始终计算有效的范围内索引值。如果url 数组发生变化,这并不重要,因为模数函数将总是计算一个有效的索引。

      const { url } = props;
      const [index, setIndex] = useState(0);
      const increment = () => setIndex(i => i + 1);
      
      useEffect(() => {
        const id = setInterval(increment, 1000);
        return () => clearInterval(id);
      }, []);
      
      const currImageIndex = index % url.length;
      
      return (
        <div className={styles.container}>
          <div className={styles.header}>Preview of GIF:</div>
          <img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
          <div>{currImageIndex}</div>
        </div>
      );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-27
        • 1970-01-01
        • 1970-01-01
        • 2017-10-09
        • 2022-09-24
        • 1970-01-01
        • 2013-08-11
        • 1970-01-01
        相关资源
        最近更新 更多