[英]Why state variables got reset on Moralis subscription in React
I am using React JS (with chakra-ui and @chatscope/chat-ui-kit-react) with Moralis Web3 creating a chat app where I want to:我正在使用 React JS(带有 chakra-ui 和 @chatscope/chat-ui-kit-react)和 Moralis Web3 创建一个我想要的聊天应用程序:
I am able to get the first step where I call a query when the component is loaded the first time using useEffect
.第一次使用useEffect
加载组件时,我能够获得调用查询的第一步。 I store it in a state variable textMsgs
.我将它存储在 state 变量textMsgs
中。
The problem is when I subscribe, in the问题是当我订阅时,在
subscription.on("create", (object) => {
console.log(textMsgs);
});
the console.log result is always empty. console.log 结果始终为空。 Whereas it should show the last array of what I fetch initially.而它应该显示我最初获取的最后一个数组。
I then add a然后我添加一个
<Button onClick={() => console.log(textMsgs)}>get textMsgs</Button>
to check if the textMsgs can show the array, and it DOES show the array.检查 textMsgs 是否可以显示数组,并且它确实显示了数组。
I'm really confused why in subscription.on, the textMsgs is empty, but when I click the button, why is it showing the first fetched when component is loaded?我真的很困惑为什么在subscription.on 中,textMsgs 是空的,但是当我单击按钮时,为什么它在加载组件时显示第一个获取?
import { Container, Button, Text } from "@chakra-ui/react";
import Moralis from "moralis/dist/moralis.min.js";
import styles from "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
import {
MainContainer,
ChatContainer,
MessageList,
Message,
MessageInput,
} from "@chatscope/chat-ui-kit-react";
import { useState, useEffect } from "react";
export const Messages = ({ roomId, userId }) => {
const [textMessage, setTextMessage] = useState("");
const [textMsgs, setTextMsgs] = useState("");
useEffect(() => {
getMessages();
subscribeMessages();
}, []);
const subscribeMessages = async () => {
const query = new Moralis.Query("Messages");
query.equalTo("roomId", roomId);
const subscription = await query.subscribe();
// on subscription object created
subscription.on("create", (object) => {
console.log(textMsgs);
});
};
// Get textMsgs in this room
const getMessages = async () => {
const Message = Moralis.Object.extend("Messages");
const message = new Moralis.Query(Message);
message.equalTo("roomId", roomId);
const msgResults = await message.find();
var msgs = [];
for (let i = 0; i < msgResults.length; i++) {
var username = await getUsername(msgResults[i].attributes.userId);
var msg = {
msgId: msgResults[i].id,
createdAt: msgResults[i].attributes.createdAt,
userId: msgResults[i].attributes.userId,
textMessage: msgResults[i].attributes.textMessage,
username: username,
};
msgs.push(msg);
}
setTextMsgs(msgs);
};
const getUsername = async (userId) => {
// Query username
const User = Moralis.Object.extend("User");
const user = new Moralis.Query(User);
user.equalTo("objectId", userId);
const userResults = await user.find();
return userResults[0].attributes.username;
};
const sendMessage = (e) => {
var newMsg = {
textMessage: textMessage,
userId: userId,
roomId: roomId,
};
const Message = Moralis.Object.extend("Messages");
const message = new Message();
message.set(newMsg);
message.save().then(
(msg) => {
// Execute any logic that should take place after the object is saved.
//alert("New object created with objectId: " + msg.id);
},
(error) => {
// Execute any logic that should take place if the save fails.
// error is a Moralis.Error with an error code and message.
alert("Failed to create new object, with error code: " + error.message);
}
);
};
return (
<Container>
{/* react chat */}
<div
style={{
height: "100vh",
}}
>
<Button onClick={() => console.log(textMsgs)}>get textMsgs</Button>
<MainContainer style={{ border: "0" }}>
<ChatContainer>
<MessageList>
<MessageList.Content>
{textMsgs &&
textMsgs.map((data, key) => {
return (
<div key={"0." + key}>
<Text
key={"1." + key}
align={data.userId === userId ? "right" : "left"}
fontSize="xs"
>
{data.username}
</Text>
<Message
model={{
message: data.textMessage,
direction:
data.userId === userId ? "outgoing" : "incoming",
sentTime: "just now",
sender: "Joe",
}}
key={"2." + key}
/>
</div>
);
})}
</MessageList.Content>
</MessageList>
<MessageInput
value={textMessage}
placeholder="Type message here"
attachButton={false}
onChange={(text) => {
setTextMessage(text);
}}
onSend={sendMessage}
/>
</ChatContainer>
</MainContainer>
</div>
</Container>
);
};
Here you can see the Messages.js:30 (in subscription.on) and Messages.js:102 (in ) showing different result在这里您可以看到 Messages.js:30 (in subscription.on) 和 Messages.js:102 (in ) 显示不同的结果
I fixed this.我解决了这个问题。 So when we want to update an array state variable, instead of trying to copy the variable and use array.push(), we must use the setState function to get the last state and use spread operator to add the new object in the array. So when we want to update an array state variable, instead of trying to copy the variable and use array.push(), we must use the setState function to get the last state and use spread operator to add the new object in the array.
Example This is the state variable, the textMsgs is filled with an array of objects, example ['apple', 'banana', 'lemon']示例 这是 state 变量,textMsgs 填充了对象数组,例如 ['apple', 'banana', 'lemon']
const [textMsgs, setTextMsgs] = useState([]);
When we want to add another object, instead of doing this first way当我们想添加另一个 object 时,而不是第一种方式
var messages = textMsgs;
messages.push('mango');
setTextMsgs(messages);
we should do the second way我们应该做第二种方式
var message = 'mango'
setTextMsgs(oldarr => [...oldarr, message])
Because in the first way, somehow when I'm fetching the data from textMsgs it's empty.因为在第一种方式中,当我从 textMsgs 获取数据时,它是空的。 I'm not sure why it happened, but if you guys have this issue you want to try the second way.我不确定它为什么会发生,但是如果你们有这个问题,你想尝试第二种方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.