React - 如何使用 useState 将数组推送到对象中
2021-01-16
1867
我正在使用 ReactJS、NestJS、Socket.io 构建聊天应用程序。
它是使用 socket.io 中的房间的多通道
const [messages, setMessages] = useState({
ReactJS: [],
NestJS: [],
Typescript: [],
MySQL: [],
Neo4j: [],
Redis: [],
ELK: [],
Docker: [],
Kubernetes: [],
AWS: [],
SocketIO: [],
});
这是用于推送消息的带有 useState 的数组。
问题
messages['ReactJS'].push(someMessage);
useState 如何使用元素将元素推送到对象内的数组?
2个回答
给定状态
const [messages, setMessages] = useState({
ReactJS: [],
NestJS: [],
Typescript: [],
MySQL: [],
Neo4j: [],
Redis: [],
ELK: [],
Docker: [],
Kubernetes: [],
AWS: [],
SocketIO: [],
});
然后,以下是通过嵌套在状态对象中的
roomKey
标识符更新特定房间的方法。在 React 中,当您更新状态时,您
必须
始终返回一个新的对象引用,这包括正在更新的任何嵌套状态/属性。
array.prototype.push
会改变原始数组,它不会为 React 目的创建新的数组引用。
setMessages(messages => ({
...messages, // <-- shallow copy state
// copy existing nested state array into new array and append new element
[roomKey]: [...messages[roomKey], newMessage],
}));
数组文字的替代方法是使用 array.prototype.concat ,它会返回一个新数组。
setMessages(messages => ({
...messages, // <-- shallow copy state
// copy existing nested state array into new array and append new element
[roomKey]: messages[roomKey].concat(newMessage),
}));
注意
:这假定您的
roomKey
变量将引用您的状态中实际定义的键之一。如果您使用未指定的密钥,则
messages[unknownKey]
将未定义。在这种情况下,如果您拥有真正的动态密钥,则可以提供后备值以扩展到状态。
setMessages(messages => ({
...messages, // <-- shallow copy state
// copy existing nested state array into new array and append new element
[roomKey]: [
...messages[roomKey] || [], // <-- provide fallback
newMessage,
],
}));
Drew Reese
2021-01-16
如果您可以安装一些其他实用程序,这里还有其他方法可以做到
Ramda
rootPath = 'ReactJS'
const newArray = R.append(someMessage, messages[rootPath])
const newMessages = R.assocPath([rootPath], newArray, messages);
setMessages(newMessages)
// combined
const rootPath = 'ReactJS'
setMessages(
R.assocPath(
[rootPath],
R.append(
someMessage,
messages[rootPath]
),
messages
)
)
Immerjs
import produce from 'immer'
const rootPath = 'ReactJS'
const newMessages = produce(messages, draftState => {
draftState[rootPath].push = someMessage
})
setMessages(newMessages)
// combined
import p from 'immer'
const rootPath = 'ReactJS'
setMessages(p(messages, draft => {
draft[rootPath].push = someMessage
}))
amirhe
2021-01-16