我的目标:
我正在尝试构建一个组件,当您为其提供 props.items
和 props.fadeEvery
时,它将充当文本旋转器。我最终希望它淡入淡出,但我的 window.setInterval
有问题。
可能的问题:
我在 setIndex
挂钩中调用 useEffect
,但这不是一个好习惯吗?我如何让它无限地遍历数组项?
TextFade.tsx
// Imports: Dependencies
import React, { useState, useEffect } from 'react';
// TypeScript Type: Props
interface Props {
items: Array<string>,
fadeEvery: number,
};
// Component: Text Fade
const TextFade: React.FC<Props> = (props): JSX.Element => {
// React Hooks: State
const [ index, setIndex ] = useState<number>(0);
// React Hooks: Lifecycle Methods
useEffect(() => {
const timeoutID: number = window.setInterval(() => {
// End Of Array
if (index > props.items.length) {
// Set Data
setIndex(0);
}
else {
// Set Data
setIndex(index + 1);
}
}, props.fadeEvery * 1000);
// Clear Timeout On Component Unmount
return () => window.clearTimeout(timeoutID);
}, []);
return (
<div id="text-fade-container">
<p id="text-fade-text">{props.items[index]}</p>
</div>
);
};
// Exports
export default TextFade;
答案 0 :(得分:2)
您的索引值取自初始闭包,除非再次调用 useEffect 回调,否则它不会更新。您可以改为使用功能方式来更新状态
useEffect(() => {
const timeoutID: number = window.setInterval(() => {
// End Of Array
setIndex(prevIdx => {
if (prevIdx > props.items.length) {
// Set Data
return 0;
}
else {
// Set Data
return prevIdx + 1;
}
})
}, props.fadeEvery * 1000);
// Clear Timeout On Component Unmount
return () => window.clearTimeout(timeoutID);
}, []);
答案 1 :(得分:1)
正如@Keith 所说:
<块引用>index 在所谓的闭包中。你的使用效果已被告知 只渲染一次 [].. 所以你需要使用回调版本 设置索引
因此,您的 useEffect
钩子将是:
useEffect(() => {
const timeoutID: number = window.setInterval(() => {
// End Of Array
if (index > props.items.length) {
// Set Data
setIndex(0);
} else {
// Set Data
setIndex(index + 1);
}
}, props.fadeEvery * 1000);
// Clear Timeout On Component Unmount
return () => window.clearTimeout(timeoutID);
}, [index]);
这是 CodeSandbox 的工作演示。
答案 2 :(得分:1)
下面我使用 setState 的回调版本编写了一个片段,这避免了使用带有 []
的 useEffect 时遇到的关闭问题..
const {useState, useEffect} = React;
const TextFade = (props) => {
// React Hooks: State
const [ index, setIndex ] = useState(0);
// React Hooks: Lifecycle Methods
useEffect(() => {
const timeoutID: number = window.setInterval(() => {
// End Of Array
setIndex(index =>
index + 1 >= props.items.length
? 0
: index + 1);
}, props.fadeEvery * 1000);
// Clear Timeout On Component Unmount
return () => window.clearInterval(timeoutID);
}, []);
return (
<div id="text-fade-container">
<p id="text-fade-text">{props.items[index]}</p>
</div>
);
};
ReactDOM.render(<TextFade items={['one','two', 'three']} fadeEvery={1}/>, document.querySelector('#mount'));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="mount"></div>