useEffect 中的 setTimeout 和 useState

setTimeout inside useEffect with useState

我的 useState 挂钩中有一组对象,我想更改每个数组元素中的一个 属性 让我们假设它看起来像:

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

虽然我试图在 useEffect 钩子中使用 setTimeout 来将 属性 displayed 不是 true 的任何地方更改为 isDisplayed: true ,它等待专用时间,并立即更改所有内容,我想要实现的是用自己的延迟更改每个元素。我的意思是像 const DELAY = 2000 和内部 setTimeout 例如 setTimeout(() => ... , DELAY * id) 因为当我渲染 jsx 时,一切都同时出现,我只想在出现每个元素之间做一些小的延迟。例如,第一个元素在 2 秒后出现,第二个在 3 秒后出现(而不是在第一个之后 3 秒)

我当前的代码如下:

React.useEffect(() => {
 setTimeout(() => {
  setArray(array.map((item)=> !item.isDisplayed ? {...item, displayed: true} : item))
 }, DELAY * Math.floor(Math.random() * 5);
}, [])
const DELAY = 2000;
React.useEffect(() => {
 let count = 1;
 array.forEach((item) => {
   if (!item.displayed) {
     setTimeout(() => {
        item.displayed = true;
        setArray([...array]);
     }, DELAY * count);
     count ++;
   }
 })
}, [])

如果某些项目不可见,您可以设置超时并触发更新。

并跟踪 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'));

这是一个fiddle