我有一个页面正在使用从数组中提取的日志消息更新模拟“控制台”。它应该工作的方式是每 n 秒一条新消息被添加到日志中。
很简单吧?只需使用 number
函数。不使用 Hooks!
这是一些(删节)代码:
setTimout
我显然在这里做了一些愚蠢的事情,因为 logIndex 的值始终为 0。有人有任何指针吗?
答案 0 :(得分:1)
我用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>
))}
</>
);
}
答案 1 :(得分:1)
你的代码是正确的,你只需要添加 logIndex,logs in use Effect 如下所示,所以 addNextLogMessage 将引用新状态。
在每次更新状态时都会创建一个新的 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);
测试一下here