gpt4 book ai didi

javascript - React Hooks,useEffect 中的 setTimeout 直到结束才触发,因为状态更新

转载 作者:行者123 更新时间:2023-12-02 02:46:54 32 4
gpt4 key购买 nike

上下文:

  • 添加新消息(例如,每两秒一次,使用 setInterval)。
  • 消息有状态,可以是旧的,也可以是新的。新添加的消息有一个"new"标志。
  • 每 5 秒后,所有"new"消息都会被指定为“旧”消息。 (设置超时)

问题:

  • 直到结束才触发超时。添加新消息,但在添加所有消息之前它们仍保持"new"状态。
  • 我怀疑每次更新后都会重置/清除超时,并且由于更新发生的速度快于超时,因此超时回调永远不会及时触发(因此只会触发最终的超时)。

function useInterval(callback, delay) {
const savedCallback = React.useRef();
// Remember the latest callback.
React.useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
React.useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}

const defaultMessages = [
{
message: "message 1",
new: false
},
{
message: "message 2",
new: false
},
{
message: "message 3",
new: true
}
];

export default function App() {
const [messages, setMessages] = React.useState(defaultMessages);
const messagesRef = React.useRef(messages);

messagesRef.current = messages;

// add a new message every 2 seconds
useInterval(() => {
messages.length < 10 &&
setMessages([
...messages,
{ message: `message ${messages.length + 1}`, new: true }
]);
}, 2000);

React.useEffect(() => {
const timer = setTimeout(() => {
// console.log("change all messages from new to old");
const updateMessages = messagesRef.current.map(m => ({
...m,
new: false
}));
setMessages([...updateMessages]);
}, 5000); // if you change this to duration less than 2 seconds then it runs just fine
return () => clearTimeout(timer); // removing the timer, calls it with every message update and seemingly ignores the timeout duration
});

return (
<div className="App">
{messages.map(m => (
<div key={m.message}>
{m.message}, status: {m.new ? "new" : "old"}
</div>
))}
</div>
);
}

示例代码:https://codesandbox.io/s/settimeout-resetting-with-updates-ufl3b

不知道如何使用 React Hooks api 来解决这个问题。每次更新后超时需要持续五秒。现在,每次暂停似乎都被取消或被后面的暂停排队。我很困惑。

谢谢!

最佳答案

嗯,我注意到的主要问题是清除下一次渲染的超时,这意味着,如果渲染速度足够快,您实际上会取消超时回调而不是运行它。

 React.useEffect(() => {
const timer = setTimeout(() => {});
// will clear the timeout on ***next*** render!
return () => clearTimeout(timer);
});

因此,修复它并使用功能更新而不是引用后,这段代码似乎有效:

export default function App() {
const [messages, setMessages] = React.useState(defaultMessages);

// add a new message every 2 seconds
useInterval(() => {
messages.length < 10 &&
setMessages(prev => [
...prev,
{ message: `message ${messages.length + 1}`, new: true }
]);
}, 2000);

React.useEffect(() => {
console.log("rendered");
setTimeout(() => {
setMessages(prev =>
prev.map(m => ({
...m,
new: false
}))
);
}, 3000);
});

return (
<div className="App">
{messages.map(m => (
<div key={m.message}>
{m.message}, status: {m.new ? "new" : "old"}
</div>
))}
</div>
);
}

Edit setTimeout resetting with updates

关于javascript - React Hooks,useEffect 中的 setTimeout 直到结束才触发,因为状态更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62641564/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com