反应:setInterval 在一个间隔后不工作
React: setInterval Not working after one interval
我的目标:
我正在尝试构建一个组件,当您给它 props.items
和 props.fadeEvery
时,它会充当文本旋转器。我最终希望它淡入淡出,但我的 window.setInterval
.
遇到了问题
可能的问题:
我在 useEffect
挂钩中调用 setIndex
,但这不是很好的做法吗?我如何让它无限遍历数组项?
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;
您的索引值取自初始闭包,除非再次调用 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);
}, []);
正如@Keith 所说:
index is in what's called a closure. Your use effect has been told to
only render once [].. So you need to use the callback version of
setIndex
因此,您的 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 上的工作演示。
下面我使用 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>
我的目标:
我正在尝试构建一个组件,当您给它 props.items
和 props.fadeEvery
时,它会充当文本旋转器。我最终希望它淡入淡出,但我的 window.setInterval
.
可能的问题:
我在 useEffect
挂钩中调用 setIndex
,但这不是很好的做法吗?我如何让它无限遍历数组项?
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;
您的索引值取自初始闭包,除非再次调用 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);
}, []);
正如@Keith 所说:
index is in what's called a closure. Your use effect has been told to only render once [].. So you need to use the callback version of setIndex
因此,您的 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 上的工作演示。
下面我使用 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>