使用 useState 进行 React hooks
2020-08-06
775
我有以下代码:
export default function App() {
const [lastMessageId, setLastMessageId] = useState(0);
const [messages, setMessages] = useState([]);
const addMessage = (body, type) => {
const newMessage = {
id: lastMessageId + 1,
type: type,
body: body,
};
setLastMessageId(newMessage.id)
setMessages([...messages, newMessage]);
console.log("point 1", messages);
return newMessage.id;
}
// remove a message with id
const removeMessage = (id) => {
const filter = messages.filter(m => m.id !== id);
console.log("point 2", filter);
setMessages(filter);
}
// add a new message and then remove it after some seconds
const addMessageWithTimer = (body, type="is-primary", seconds=5) => {
const id = addMessage(body, type);
setTimeout(() => removeMessage(id), seconds*1000);
};
return (
...
);
}
我想知道为什么在第 1 点设置消息后,当我进行控制台记录时,它似乎没有更新。当我调用 addMessageWithTimer 时,这变成了一种奇怪的行为,因为当它调用 removeMessage 时,它不会正确删除我期望的消息。
你能解释一下怎么做吗?
3个回答
就像类组件中的
setState
一样,
useState
的更新函数不会立即更新状态,它们会
安排
状态进行更新。
当您调用
setMessages
时,它会导致 React 安排
App
的新渲染,这将再次执行
App
函数,并且
useState
将返回
messages
的新值。
如果您从纯 JS 的角度考虑,
messages
无法
改变:它只是一个局部变量(甚至是
const
变量)。调用非局部函数不会导致局部变量的值发生变化,JS 不是那样工作的。
Retsam
2020-08-06
@Retsam 的解释是正确的。
我认为,如果您在 addMessageWithTimer 中不使用 setTimeout,就会出现问题。不是吗?但就目前而言,这是正确的。
如果您不想给出 5 秒的计时器,但仍想让它正常运行,那么给出 0 秒的计时器。它仍然可以正常工作。
Ravi Garg
2020-08-06
您看到了什么奇怪的行为?
当我尝试您的代码时,我能够在 5 秒后删除添加的消息。
import React, { useState } from "react";
import "./styles.css";
export default function App() {
let bodyText = "";
const [lastMessageId, setLastMessageId] = useState(0);
const [messages, setMessages] = useState([]);
const addMessage = (body, type) => {
if (body === "") return;
const newMessage = {
id: lastMessageId + 1,
type: type,
body: body
};
setLastMessageId(newMessage.id);
setMessages([...messages, newMessage]);
bodyText = "";
return newMessage.id;
};
// remove a message with id
const removeMessage = (id) => {
const filter = messages.filter((m) => m.id !== id);
console.log("point 2", filter);
setMessages(filter);
};
// add a new message and then remove it after some seconds
const addMessageWithTimer = (body, type = "is-primary", seconds = 5) => {
const id = addMessage(body, type);
setTimeout(() => removeMessage(id), seconds * 1000);
};
console.log("point 1", messages);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<input onChange={(e) => (bodyText = e.target.value)} />
<button onClick={(e) => addMessage(bodyText, "is-primary")}>
Add messsage
</button>
<button onClick={(e) => addMessageWithTimer(bodyText, "is-primary", 5)}>
Add temp messsage
</button>
{messages.map((message, id) => {
return (
<div key={id}>
<p>
{message.id} {message.body}
</p>
</div>
);
})}
</div>
);
}
frontEnd
2020-08-06