如何在 React 中每秒递增一个状态变量
How to increment a state variable every second in React
我的代码中有一个名为“url”的组件的图像列表。我还有一个名为 currImageIndex
的状态变量。我想要发生的是每次渲染这个组件时,我想启动一个计时器。这个计时器每秒 运行s,我想增加我的状态变量 currImageIndex
。当 currImageIndex + 1
大于或等于 url
长度时,我想将 currImageIndex
重置为零。总体目标是通过返回 <img src={url[currImageIndex]}>
来模拟图像的自动幻灯片放映。但是,我在增加状态变量时遇到问题。我按照我在此处找到的一些代码进行操作,但我无法弄清楚如何使增量工作。这是我的代码。
const { url } = props;
const [currImageIndex, setCurrImageIndex] = useState(0);
console.log(url)
const increment = () => {
console.log(url.length)
console.log(currImageIndex)
if (currImageIndex + 1 < url.length) {
setCurrImageIndex((oldCount) => oldCount + 1)
}
else {
setCurrImageIndex(0)
}
}
useEffect(() => {
const id = setInterval(increment, 1000);
return () => clearInterval(id);
}, []);
return (
<div className={styles.container}>
<div className={styles.header}>Preview of GIF:</div>
<img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
<div>{currImageIndex}</div>
</div>
);
当我 运行 使用大小为 2 的 url
时,倒数第三行(“{currImageIndex}”)显示 1,然后是 2,然后是 3,依此类推。它永远不会重置。我的 console.log(url.length)
打印 2,我的 console.log(currImageIndex)
打印 0。我想要发生的是 currImageIndex
应该是 0, 1, 0, 1, 0, 1,.... 谁能帮忙我明白我做错了什么吗?谢谢!
原因是在 setInterval 上传递的回调仅访问第一次渲染中的 currImageIndex
变量,而不是渲染时的新值,因此您将始终获得 currImageIndex = 0
并传递条件 if (currImageIndex + 1 < url.length)
。我更新了您的代码并使其按您的期望工作:https://stackblitz.com/edit/react-y6fqwt
问题
这里的问题是,当在间隔计时器中设置 increment
回调时,初始渲染中的 currImageIndex
状态值已过时。您正确地使用功能状态来增加 currImageIndex
值,但是 increment
函数体中的 currImageIndex
值始终是初始状态值 [=18] =].
解决方案
这里的一个常见解决方案是使用 React ref 来缓存 currImageIndex
状态,以便可以在回调中访问当前值。
示例:
const [currImageIndex, setCurrImageIndex] = useState(0);
const currentImageIndexRef = useRef();
useEffect(() => {
// cache the current state value
currentImageIndexRef.current = currentImageIndex;
}, [currImageIndex]);
const increment = () => {
// access the current state value
if (currentImageIndexRef.current + 1 < url.length) {
setCurrImageIndex((oldCount) => oldCount + 1)
}
else {
setCurrImageIndex(0)
}
}
useEffect(() => {
const id = setInterval(increment, 1000);
return () => clearInterval(id);
}, []);
一个更简单的解决方案是只访问 url
值,该值在组件范围内通过状态更新器回调关闭。使用三元运算符检查当前值加 1 是否仍然小于 url
长度和状态 + 1,否则通过返回 0
重置。但是请注意,如果 url
数组是动态的并且长度发生变化,则此解决方案会因同样的原因而中断,初始渲染中的 url
值将在范围内关闭。
const increment = () => {
setCurrImageIndex((count) => count + 1 < url.length ? count + 1 : 0);
}
而 IMO 最简单的解决方案是始终增加 currImageIndex
状态并取 url
长度的模数以始终计算有效的范围内索引值。如果 url
数组发生变化,这并不重要,因为模数函数将 始终 计算出有效索引。
const { url } = props;
const [index, setIndex] = useState(0);
const increment = () => setIndex(i => i + 1);
useEffect(() => {
const id = setInterval(increment, 1000);
return () => clearInterval(id);
}, []);
const currImageIndex = index % url.length;
return (
<div className={styles.container}>
<div className={styles.header}>Preview of GIF:</div>
<img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
<div>{currImageIndex}</div>
</div>
);
我的代码中有一个名为“url”的组件的图像列表。我还有一个名为 currImageIndex
的状态变量。我想要发生的是每次渲染这个组件时,我想启动一个计时器。这个计时器每秒 运行s,我想增加我的状态变量 currImageIndex
。当 currImageIndex + 1
大于或等于 url
长度时,我想将 currImageIndex
重置为零。总体目标是通过返回 <img src={url[currImageIndex]}>
来模拟图像的自动幻灯片放映。但是,我在增加状态变量时遇到问题。我按照我在此处找到的一些代码进行操作,但我无法弄清楚如何使增量工作。这是我的代码。
const { url } = props;
const [currImageIndex, setCurrImageIndex] = useState(0);
console.log(url)
const increment = () => {
console.log(url.length)
console.log(currImageIndex)
if (currImageIndex + 1 < url.length) {
setCurrImageIndex((oldCount) => oldCount + 1)
}
else {
setCurrImageIndex(0)
}
}
useEffect(() => {
const id = setInterval(increment, 1000);
return () => clearInterval(id);
}, []);
return (
<div className={styles.container}>
<div className={styles.header}>Preview of GIF:</div>
<img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
<div>{currImageIndex}</div>
</div>
);
当我 运行 使用大小为 2 的 url
时,倒数第三行(“{currImageIndex}”)显示 1,然后是 2,然后是 3,依此类推。它永远不会重置。我的 console.log(url.length)
打印 2,我的 console.log(currImageIndex)
打印 0。我想要发生的是 currImageIndex
应该是 0, 1, 0, 1, 0, 1,.... 谁能帮忙我明白我做错了什么吗?谢谢!
原因是在 setInterval 上传递的回调仅访问第一次渲染中的 currImageIndex
变量,而不是渲染时的新值,因此您将始终获得 currImageIndex = 0
并传递条件 if (currImageIndex + 1 < url.length)
。我更新了您的代码并使其按您的期望工作:https://stackblitz.com/edit/react-y6fqwt
问题
这里的问题是,当在间隔计时器中设置 increment
回调时,初始渲染中的 currImageIndex
状态值已过时。您正确地使用功能状态来增加 currImageIndex
值,但是 increment
函数体中的 currImageIndex
值始终是初始状态值 [=18] =].
解决方案
这里的一个常见解决方案是使用 React ref 来缓存 currImageIndex
状态,以便可以在回调中访问当前值。
示例:
const [currImageIndex, setCurrImageIndex] = useState(0);
const currentImageIndexRef = useRef();
useEffect(() => {
// cache the current state value
currentImageIndexRef.current = currentImageIndex;
}, [currImageIndex]);
const increment = () => {
// access the current state value
if (currentImageIndexRef.current + 1 < url.length) {
setCurrImageIndex((oldCount) => oldCount + 1)
}
else {
setCurrImageIndex(0)
}
}
useEffect(() => {
const id = setInterval(increment, 1000);
return () => clearInterval(id);
}, []);
一个更简单的解决方案是只访问 url
值,该值在组件范围内通过状态更新器回调关闭。使用三元运算符检查当前值加 1 是否仍然小于 url
长度和状态 + 1,否则通过返回 0
重置。但是请注意,如果 url
数组是动态的并且长度发生变化,则此解决方案会因同样的原因而中断,初始渲染中的 url
值将在范围内关闭。
const increment = () => {
setCurrImageIndex((count) => count + 1 < url.length ? count + 1 : 0);
}
而 IMO 最简单的解决方案是始终增加 currImageIndex
状态并取 url
长度的模数以始终计算有效的范围内索引值。如果 url
数组发生变化,这并不重要,因为模数函数将 始终 计算出有效索引。
const { url } = props;
const [index, setIndex] = useState(0);
const increment = () => setIndex(i => i + 1);
useEffect(() => {
const id = setInterval(increment, 1000);
return () => clearInterval(id);
}, []);
const currImageIndex = index % url.length;
return (
<div className={styles.container}>
<div className={styles.header}>Preview of GIF:</div>
<img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
<div>{currImageIndex}</div>
</div>
);