Issue
- The for-loop is completely synchronous code. When updating react state in a loop you must use a functional state update, otherwise each subsequent enqueued update overwrites the previous update.
- The for-loop is in the component body which means each time the component rerenders due to the state update, another set of enqueue state updates will be set.
Solution
If you wanted to queue up all updates in a synchronous loop then it should be done once in a mounting useEffect
hook and apply a delta to the timeouts so they don't all expire at the same time.
useEffect(() => {
items.forEach((item, i) => setTimeout(
() => setMediaItem(item),
(i + 1) * 5000, // 5000, 10000, 15000
));
}, []);
It may be a bit easier to use/store an array index
in state and increment that on an interval.
const items = [{ name: "one" }, { name: "two" }, { name: "three" }];
function AppExample() {
const [mediaItem, setMediaItem] = React.useState(items[0]); // <-- seed initial state
const [index, setIndex] = React.useState(0);
React.useEffect(() => {
const timerId = setInterval(
() => setIndex((i) => (i + 1) % items.length), // <-- increment index
2000
);
return () => clearInterval(timerId);
}, []);
React.useEffect(() => {
setMediaItem(items[index]); // <-- update media state when index updates
}, [index]);
return (
<div className="App">
<div>Media: {mediaItem.name}</div>
</div>
);
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…