如何使用React钩子递归地正确设置setTimeout



我正在构建一个组件,该组件应该显示数组的元素,每次一个,并在由数据确定的一段时间内显示元素。使用下面的数据,我想显示文本A 5秒,然后更改为文本B,显示20秒,然后显示文本C 10秒,然后重新开始,显示文本A,依此类推

以下是我正在尝试的:

const slides = [
{text: 'textA, time_length: 5},
{text: 'textB', time_length: 20},
{text: 'textC', time_length: 10}
] ;
const play = () => {
if (slides && slides.length > 0) {
const playSlides = () => {               
this.timer = setTimeout(() => {
// update index
if (currentIndex + 1 < splashes.length) {
setCurrentIndex(currentIndex + 1)
} else {
setCurrentIndex(0)
}
}, slides[currentIndex])             
}
}
}
useEffect(() => {
if (slides.length) {
debugger
play(slides)
}
return clearTimeout(this.timer)
}, [slides])
return <p>{slides[currentIndex]}</p>
}

此解决方案将在每个slide.time_length显示slide.text。请注意,"循环"是通过依赖关系[currentIndex]实现的;换句话说,每次currentIndex发生变化时,useEffect将再次运行,并在下一个time_length秒后更新currentIndex

如果计算(currentIndex + 1) % slides.length溢出数组长度,它将把索引重置回0(这只是条件的缩短版本,没有什么特别的(。

const slides = [
{ text: 'textA', time_length: 5 },
{ text: 'textB', time_length: 20 },
{ text: 'textC', time_length: 10 }
];
const TextSlider = () => {
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
if (slides.length) {
const timeoutId = setTimeout(() => {
setCurrentIndex((currentIndex + 1) % slides.length)
}, slides[currentIndex].time_length * 1000)
return () => clearTimeout(timeoutId);
}
return () => { }
}, [currentIndex])
return <h1>{slides[currentIndex].text}</h1>
}

有时不那么罗嗦可以让你更容易地了解发生了什么。你的里程数可能会有所不同-

import { useState, useEffect } from "react"
function TextSlider ({ slides = [] }) {
const [i, nextSlide] =
useState(0)
useEffect(() => {
if (i >= slides.length) return
const t =
setTimeout
( nextSlide
, slides[i].time_length * 1000
, (i + 1) % slides.length
)
return () => clearTimeout(t)
}, [i])
return <h1>{slides[i].text}</h1>
}
ReactDom.render(document.body, <TextSlider slides={slides} />)

最新更新