简体   繁体   English

使用 useState 在 useEffect 中设置超时

[英]setTimeout inside useEffect with useState

I have array of objects inside my useState hook, and I would like to change one property of each array element let's say it looks like:我的 useState 钩子中有对象数组,我想更改每个数组元素的一个属性,假设它看起来像:

const array = [{id:1, isDisplayed: false}, {id:2, isDisplayed: false}, {id:3, isDisplayed: true}]

and while Im trying to use setTimeout inside useEffect hook to change property displayed everywhere where it's not true to isDisplayed: true , it waits for the dedicated time, and changes everything at once, what I want to achieve is to change each element with its own delay.同时我试着去使用setTimeout里面useEffect钩把属性displayed无处不在那里它不是trueisDisplayed: true ,它等待专门的时间,立刻改变了一切,我想要实现的是改变每个元素都有自己的延迟。 I mean something like const DELAY = 2000 and inside setTimeout for instance setTimeout(() => ... , DELAY * id) because in place when I render jsx, everything appears all at once, and i just want to make small delays between appearing each element.我的意思是像const DELAY = 2000和 setTimeout 之类的东西,例如setTimeout(() => ... , DELAY * id)因为当我渲染 jsx 时,一切都同时出现,我只想在两者之间做一些小的延迟出现每个元素。 For instance, first element appears after 2s, second after 3s (not 3s after first one)例如,第一个元素出现在 2s 之后,第二个出现在 3s 之后(不是第一个之后的 3s)

My current code looks like:我当前的代码如下所示:

React.useEffect(() => {
 setTimeout(() => {
  setArray(array.map((item)=> !item.isDisplayed ? {...item, displayed: true} : item))
 }, DELAY * Math.floor(Math.random() * 5);
}, [])

You can set a timeout and trigger an update, if some items are not visible.如果某些项目不可见,您可以设置超时并触发更新。

And track if new items are revealed with revealed and if no new items were revealed, stop the flow.并跟踪,如果新项目揭示了与revealed ,如果没有新的项目被发现,停止流动。

function TodoApp() {
  const [items, setItems] = React.useState([
    { id: 1, isDisplayed: false },
    { id: 2, isDisplayed: false },
    { id: 3, isDisplayed: false },
  ]);
  React.useEffect(() => {
    let currentTimeout = null;
    const displayMoreItems = () => {
      setItems(prevItems => {
        let revealed = false;
        const nextItems = prevItems.map(item => {
          if (!revealed && !item.isDisplayed) {
            revealed = true;
            return { ...item, isDisplayed: true };
          }
          return item;
        });
        if (revealed) {
          currentTimeout = setTimeout(() => {
            displayMoreItems();
          }, 1000);
        }
        return nextItems;
      });
    };
    currentTimeout = setTimeout(() => {
      displayMoreItems();
    }, 1000);
    return () => {
      if (currentTimeout) {
        clearTimeout(currentTimeout);
      }
    };
  }, [setItems]);
  return <div>{items.map(item => (item.isDisplayed ? item.id : null))}</div>;
}

ReactDOM.render(<TodoApp />, document.querySelector('#app'));

Here is a fiddle这是一个小提琴

const DELAY = 2000;
React.useEffect(() => {
 let count = 1;
 array.forEach((item) => {
   if (!item.displayed) {
     setTimeout(() => {
        item.displayed = true;
        setArray([...array]);
     }, DELAY * count);
     count ++;
   }
 })
}, [])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM