【问题标题】:Javascript - How to loop through an array over and over again in ReactJavascript - 如何在 React 中一遍又一遍地遍历数组
【发布时间】:2022-01-04 16:21:31
【问题描述】:

想象一下我有一个这样的对象数组:

const items = [
    {name: "item 0"},
    {name: "item 1"},
    {name: "item 2"}
]

还有一个像这样的组件:

const [currentItemIndex, setCurrentItemIndex] = useState(0)

setInterval(function () {
   if (currentItemIndex < 3) {
      setCurrentItemIndex(currentItemIndex + 1);
   } else {
      clearInterval();
   }
}, 5000);
   
return (
    <div>
        <p> {items[currentItemIndex].name} <p>
    </div>
)

我想每 5 秒更新一次 currentItemIndex,以便 div 显示下一项,如果它到达末尾,它应该重新开始:0, 1, 2, 0, 1, 2, 0, 1, 2 ...

问题是:它第一次循环正确,但到达结尾后,它显示第一个项目不到一秒钟,然后转到最后一个项目:0, 1, 2, 0 (really quick to) 2

我做错了什么?
我搜索了这个,但每篇文章都在谈论“如何防止无限循环”,而不是“如何使用它们”!

【问题讨论】:

  • 而不是setCurrentItemIndex(currentItemIndex + 1) 你可以试试setCurrentItemIndex( val =&gt; (val + 1))
  • 您需要使用useEffect 来处理setTimeout 之类的效果 - 例如stackoverflow.com/questions/57542264/…
  • 首先,您对clearInterval 的使用是不正确的,并没有做任何事情。其次,您的循环永远不会从头开始,因为您从未重置计数器。
  • 您需要将currentItemIndex 移回零的东西,然后您可以继续增加它。因此,您可以像这样添加检查setCurrentItemIndex((currentItemIndex + 1) % items.length);
  • @SaadMehmood 好主意。

标签: javascript reactjs


【解决方案1】:

您可以使用useEffectsetTimeout 这样做:

const items = [{ name: "item 0" }, { name: "item 1" }, { name: "item 2" }];

const App = () => {
  const [currentItemIndex, setCurrentItemIndex] = React.useState(0);

  React.useEffect(() => {
    const id = setTimeout(
      () => setCurrentItemIndex((currentItemIndex + 1) % items.length),
      1000
    );
    return () => {
      clearInterval(id); // removes React warning when gets unmounted
    };
  }, [currentItemIndex]);

  return (
    <div>
      <p> {items[currentItemIndex].name} </p>
    </div>
  );
};

// export default App;

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

【讨论】:

    【解决方案2】:

    我发现您创建的这个逻辑存在一些问题。

    首先,clearInterval 需要提供一个您在创建setInterval 函数时创建的变量(如您所见here),所以这个clearInterval() 什么都不做。

    除此之外,您不想在currentItemIndex 达到其阈值时清除计时器,而是希望它回到零。

    在 React 中,我们通常将 useEffect 用于计时事件,因为您需要在卸载时清除它们,这样您就不会在卸载组件后继续运行它们。像这样的:

    useEffect(() => {
        const timer = setInterval(yourFunction);
        return () => clearInterval(timer);
    }, [])
    

    【讨论】:

      【解决方案3】:

      如果您愿意,可以使用此方法。您创建一个函数,使用该函数将在 5 秒后使用超时设置状态。设置状态后,您将再次调用相同的方法。 为了反应,您使用 useEffect 调用此方法一次。

      import { useEffect, useState } from "react";
      
      
      const items = [{ name: "item 0" }, { name: "item 1" }, { name: "item 2" }];
      
      
      export default function App() {
        const [currentItemIndex, setCurrentItemIndex] = useState(0);
      
        useEffect(() => {
          incrementAfterDelay(1000, 1, 2);
        }, []);
      
        const incrementAfterDelay = (delay, step, lastStep) => {
          setTimeout(
            () =>
              setCurrentItemIndex((value) => {
                return (value < lastStep)? value + step : 0
              }, incrementAfterDelay(delay, step, lastStep)),
            delay
          );
        };
      
        return (
          <div>
            <p> {items[currentItemIndex].name} </p>
          </div>
        );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-30
        相关资源
        最近更新 更多