![](/img/trans.png)
[英]Function not pointing to the updated value of state variable using hooks
[英]React Hooks state variable not updated during setTimeout function
我有一个页面正在使用从数组中提取的日志消息更新模拟“控制台”。 它应该工作的方式是每n秒将一条新消息添加到日志中。
很简单,对吧? 只需使用setTimout
function。 不是用钩子!
这是一些(删节的)代码:
const [logIndex, setLogIndex] = useState(0);
const [logs, setLogs] = useState([]);
let interval = useRef(setTimeout(() => {}, 0);
useEffect(() => {
interval.current = setTimeout(addNextLogMessage, 2000);
return(() => {
clearTimeout(interval.current); // cleanup
}
}, []); // run when page first loads
const sourceLogs = [
<p>Message 1</p>,
<p>Message 2</p>,
<p>Message 3</p>,
<p>Message 4</p>,
<p>Message 5</p>,
<p>Message 6</p>
];
const timeBetweenMessages = Math.ceil((1000 * 60 * 3) / sourceLogs.length); // three minutes (1000ms * 60sec * 3min) divided into number of log messages, rounded up
const addNextLogMessage () => {
setLogIndex(logIndex => logIndex + 1);
clearTimeout(interval.current);
if(logIndex < sourceLogs.length) {
setLogs(logs => [...logs, {...sourceLogs[logIndex], timeStamp: new Date().toString()}]);
interval.current = setTimeout(addNextLogMessage, Math.random() * timeBetweenMessages + 500);
}
}
return (
<>
{
logs.map(item => item);
}
</>
);
我显然在这里做一些愚蠢的事情,因为 logIndex 的值始终为 0。有人有任何指针吗?
我用codeandbox为你做了一个解决方案。 这种行为是必需的吗? 我只是遵循控制台警告建议,就是这样:
https://codesandbox.io/s/late-tree-01bqh?file=/src/App.js
这是其中的代码:
import React, {
useMemo,
useCallback,
useState,
useRef,
useEffect
} from "react";
import "./styles.css";
export default function App() {
const [logIndex, setLogIndex] = useState(0);
const [logs, setLogs] = useState([]);
const sourceLogs = useMemo(
() => [
<p>Message 1</p>,
<p>Message 2</p>,
<p>Message 3</p>,
<p>Message 4</p>,
<p>Message 5</p>,
<p>Message 6</p>
],
[]
);
let interval = useRef(setTimeout(() => {}, 0));
const timeBetweenMessages = Math.ceil((1000 * 60 * 3) / sourceLogs.length); // three minutes (1000ms * 60sec * 3min) divided into number of log messages, rounded up
const addNextLogMessage = useCallback(() => {
setLogIndex((logIndex) => logIndex + 1);
clearTimeout(interval.current);
if (logIndex < sourceLogs.length) {
setLogs((logs) => [
...logs,
{ ...sourceLogs[logIndex], timeStamp: new Date().toString() }
]);
interval.current = setTimeout(
addNextLogMessage,
Math.random() * timeBetweenMessages + 500
);
}
}, [logIndex, sourceLogs, timeBetweenMessages]);
useEffect(() => {
interval.current = setTimeout(addNextLogMessage, 2000);
return () => {
clearTimeout(interval.current); // cleanup
};
}, [addNextLogMessage]);
return (
<>
{logs.map((item, i) => (
<div key={`${i}-item`}>{item}</div>
))}
</>
);
}
您的代码是正确的,您只需添加 logIndex,logs 使用效果括号,如下所示,因此 addNextLogMessage 将引用新的 state。
在每次更新 state 时,都会创建一个新的 addNextLogMessage,如果您没有用新的(addNextLogMessage)更新间隔,它仍将引用第一个 logIndex 等于 0 的间隔,因此它将始终显示“消息 1”
import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [logs, setLogs] = useState([]);
const [timeOut, setTimeOut] = useState(2000);
const interval = useRef(setTimeout(() => {}, 0));
const [logIndex, setLogIndex] = useState(0);
useEffect(() => {
interval.current = setTimeout(addNextLogMessage, timeOut);
return () => {
clearTimeout(interval.current); // cleanup
};
}, [logIndex, logs]);
const sourceLogs = [
<p>Message 1</p>,
<p>Message 2</p>,
<p>Message 3</p>,
<p>Message 4</p>,
<p>Message 5</p>,
<p>Message 6</p>
];
const timeBetweenMessages = Math.ceil((1000 * 60 * 3) / sourceLogs.length);
const addNextLogMessage = () => {
setTimeOut(Math.random() * timeBetweenMessages + 500);
setLogIndex((logIndex) => logIndex + 1);
if (logIndex < sourceLogs.length) {
setLogs((logs) => [
...logs,
{ ...sourceLogs[logIndex], timeStamp: new Date().toString() }
]);
}
};
return <>{logs.map((item) => item)}</>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
在这里测试
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.