3 回答
TA贡献1772条经验 获得超5个赞
让您的组件在索引更改时由其状态驱动,它会触发更新 currentFruit 状态的 useEffect 挂钩,currentFruit 更改会触发另一个更新索引的 useEffect 等等,然后只需使用 like setTimeout:
const IntervalExample = () => {
const fruits = [
{id: 1, name: "Orange", duration: 2000},
{id: 2, name: "Kiwi", duration: 1000},
{id: 3, name: "Mango", duration: 3000},
]
const [index, setIndex] = useState(0);
const [currentFruit, setCurrentFruit] = useState(fruits[index]);
useEffect(() => {
setCurrentFruit(fruits[index])
}, [index])
useEffect(() => {
const interval = setTimeout(() => {
setIndex(index === fruits.length - 1 ? 0 : index + 1)
}, currentFruit.duration);
}, [currentFruit])
return (
<div className="App">
<header className="App-header">
{currentFruit.name}: {currentFruit.duration}
</header>
</div>
);
};
TA贡献1802条经验 获得超4个赞
UseEffect 只被调用一次。因此,Const interval将为时间间隔的函数调用初始化一个闭包。它永远不会改变。关闭中的索引将始终为 0。
这是我的解决方案,只需使用一种状态作为索引:
const IntervalExample = () => {
const fruits = [
{id: 1, name: "Orange", duration: 2000},
{id: 2, name: "Kiwi", duration: 1000},
{id: 3, name: "Mango", duration: 3000},
]
const [index, setIndex] = useState(0);
//because fruit depend on index. Dont need a separate state
const currentFruit = fruits[index];
const handleIndex = () => {
setIndex(index === fruits.length - 1 ? 0 : index + 1)
}
useEffect(() => {
//after render current fruit. We new timeout to set next fruit.
setTimeout(handleIndex, currentFruit.duration);
}, [index]);
return (
<div className="App">
<header className="App-header">
{currentFruit.name}: {currentFruit.duration}
</header>
</div>
);
};
TA贡献1796条经验 获得超4个赞
如果你想为每个水果使用不同的超时,那setTimeout将是更好的方法。
由于在初始值setInterval被调用时会被设置为改变显示水果信息的时间间隔。useEffect
您的代码中的问题是在更新index状态时未正确更新。
为了解决这个问题而不是直接更新值,我使用更新后的状态值,如下所示
setIndex((index) => (index === fruits.length - 1 ? 0 : index + 1))
const { useState, useEffect } = React;
const fruits = [
{ id: 1, name: "Orange", duration: 2000 },
{ id: 2, name: "Kiwi", duration: 1000 },
{ id: 3, name: "Mango", duration: 3000 }
];
const IntervalExample = () => {
const [index, setIndex] = useState(0);
const [currentFruit, setCurrentFruit] = useState(fruits[0]);
useEffect(() => {
const interval = setInterval(() => {
setIndex((index) => (index === fruits.length - 1 ? 0 : index + 1));
}, fruits[index].duration);
return () => clearInterval(interval);
}, []);
useEffect(() => {
setCurrentFruit(fruits[index]);
}, [index]);
return (
<div className="App">
<header className="App-header">
{currentFruit.name}: {currentFruit.duration}
</header>
</div>
);
};
ReactDOM.render(
<IntervalExample />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
添加回答
举报