使用 React Hooks 实现更改文本的无限循环



我正在尝试构建一个类似于typed.js的组件,从某种意义上说,文本(来自数组(将被无限期地循环。以下是我到目前为止拥有的这个组件(使用样式化组件(:

const cdRotateIn = keyframes`
0% {
transform: rotateX(180deg);
opacity: 0;
}
35% {
transform: rotateX(120deg);
opacity: 0;
}
65% {
opacity: 0;
}
100% {
transform: rotateX(360deg);
opacity: 1;
}
`
const cdRotateOut = keyframes`
0% {
transform: rotateX(0deg);
opacity: 1;
}
35% {
transform: rotateX(-40deg);
opacity: 1;
}
65% {
opacity: 0;
}
100% {
transform: rotateX(180deg);
opacity: 0;
}
`
const Wrapper = styled.div``
const Headline = styled.h1``
const StaticText = styled.span``
const AnimatedTextContainer = styled.span`
display: inline-block;
perspective: 300px;
`
const AnimatedText = styled.b`
opacity: 0;
transform-origin: 50% 100%;
transform: rotateX(180deg);
display: inline-block;
position: absolute;
left: 0;
top: 0;
${ifProp('isVisible', css`
position: relative;
opacity: 1;
transform: rotateX(0deg);
animation: ${cdRotateIn} 1.2s;
`)}
${ifProp('isHidden', css`
transform: rotateX(180deg);
animation: ${cdRotateOut} 1.2s;
`)}
`
const FlipAnimation = ({ words }) => {
const [currentIndex, setCurrentIndex] = useState(0)
const animationDelay = 1000
useEffect(() => {
let loopInterval = setInterval(() => {
animateHeadline(words)
}, animationDelay)
return () => {
clearInterval(loopInterval)
}
}, [])

const animateHeadline = (words) => {
setInterval(() => {
setNextIndex()
}, animationDelay);
}
const setNextIndex = () => {
if (currentIndex < words.length - 1) {
setCurrentIndex(currentIndex + 1)
} else {
setCurrentIndex(0)
}
}
const animatedTexts = () => words.map((word, index) =>
<AnimatedText key={index} isVisible={currentIndex === index} isHidden={currentIndex !== index}>{word}</AnimatedText>
)
return (
<Wrapper>
<Headline>
<StaticText>My favourite food is</StaticText>
<AnimatedTextContainer>
{animatedTexts()}
</AnimatedTextContainer>
</Headline>
</Wrapper>
)
}
FlipAnimation.defaultProps = {
words: ['bacon', 'eggs', 'sausage']
}

我可以在调试控制台中看到的问题是 currentIndex 在每次运行循环时都没有正确更新。我不明白为什么会发生这种情况,因为这段代码每秒运行一次:

if (currentIndex < words.length - 1) {
setCurrentIndex(currentIndex + 1)
} else {
setCurrentIndex(0)
}

您的函数从第一次渲染开始关闭currentIndex变量。因此,currentIndex始终为 0,setCurrentIndex(currentIndex + 1)将始终尝试将其设置为 1。

解决此问题的一个选项是确保每次都创建一个新函数,并使用该新函数设置新的超时。这样,每个新函数都会在最近的值上关闭。但是,有一种更简单的方法:setCurrentIndex 允许您将函数传递到其中,该函数将使用当前值恰好是什么来调用。然后,您可以基于此计算新值:

setCurrentIndex(previousVal => {
if (previousVal < words.length - 1) {
return previousVal + 1;
}
return 0;
});

最新更新