问题
Hi currently im trying to create a simple group chat apps. when i use this on useEffect
useEffect(() => {
// i want to fetch data from the backend first and concat it with the msg that will be send during the chat
handleGetGroupMessage();
let socket = io(socketUrl);
socket.on("GroupChat", (msg) => {
console.log("this is the chat messages", chatMessages);
setChatMessages(chatMessages.concat(msg));
});
}, []);
when the apps is loaded all the messages from my backend was stored in that state. but when i send a new message all the array was replaced with chat object. so i console.log the chatMessages state and it was an empty array. what i want is to concat previous state with the msg object
note : chatMessages state is an array of object
here's my full conde
import React, { useEffect, useState, useContext } from "react";
import {
View,
StyleSheet,
SafeAreaView,
FlatList,
Text,
TouchableHighlight,
Keyboard,
} from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import Constants from "expo-constants";
import colors from "../config/colors";
import { TextInput } from "react-native-gesture-handler";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { sendMessage, getGroupMessage } from "../api/chatApi";
import io from "socket.io-client";
import AuthContext from "../auth/AuthContext";
import { socketUrl } from "../config/url";
import axios from "axios";
import { apiUrl } from "../config/url";
const GroupChatScreen = (props) => {
const authContext = useContext(AuthContext);
const [chatMessages, setChatMessages] = useState([]);
const [chat, setChat] = useState(null);
const handleSendMessage = async (chat) => {
const result = await sendMessage({ chat }, authContext.token);
setChat(null);
Keyboard.dismiss();
let socket = io(socketUrl);
socket.emit("GroupChat", result);
};
const handleGetGroupMessage = () => {
axios
.get(`${apiUrl}/messages/group`, {
headers: { token: authContext.token },
})
.then((data) => {
setChatMessages(data.data);
})
.catch((error) => {
console.log(error);
});
};
useEffect(() => {
// i want to fetch data from the backend first and concat it with the msg that will be send
console.log(authContext.userData, "userdata");
handleGetGroupMessage();
let socket = io(socketUrl);
socket.on("GroupChat", (msg) => {
console.log("this is the chat messages", chatMessages);
setChatMessages(chatMessages.concat(msg));
});
}, []);
return (
<LinearGradient
colors={[colors.BLUE, colors.DARKBLUE]}
style={styles.container}
>
<View style={styles.chatTitleContainer}>
<Text style={styles.chatTitle}>Pub Chat</Text>
</View>
<FlatList
style={styles.flatList}
keyExtractor={(item) => item.ChatId.toString()}
data={chatMessages}
renderItem={({ item }) => {
if (item.from === authContext.userData.id) {
return (
<View style={styles.fromMe}>
<View style={styles.myChatContainer}>
<Text style={styles.myChat}>{item.chat}</Text>
</View>
</View>
);
} else {
return (
<View style={styles.fromYou}>
<Text style={styles.yourUsername}>{item.username}</Text>
<View style={styles.yourChatContainer}>
<Text style={styles.yourChat}>{item.chat}</Text>
</View>
</View>
);
}
}}
></FlatList>
<View style={styles.textInputContainer}>
<TextInput
onChangeText={(text) => setChat(text)}
style={styles.textInput}
value={chat}
placeholder="Enter Chat Here"
/>
<TouchableHighlight
onPress={() => handleSendMessage(chat)}
style={styles.roundButton}
>
<MaterialCommunityIcons
name="send"
color="white"
size={30}
style={styles.roundButtonIcon}
/>
</TouchableHighlight>
</View>
</LinearGradient>
);
};
export default GroupChatScreen;
const styles = StyleSheet.create({
chatTitle: {
fontSize: 20,
padding: 10,
color: "white",
textAlign: "center",
},
chatTitleContainer: {
backgroundColor: "#031f47",
width: "110%",
height: 40,
justifyContent: "center",
alignContent: "center",
},
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: Constants.statusBarHeight,
},
flatList: {
width: "90%",
},
textInput: {
width: "80%",
height: 50,
backgroundColor: "white",
marginRight: 8,
borderRadius: 10,
paddingLeft: 20,
fontSize: 20,
},
textInputContainer: {
width: "100%",
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
marginLeft: 10,
},
roundButton: {
height: 60,
width: 60,
alignContent: "center",
justifyContent: "center",
backgroundColor: "#042048",
borderRadius: 90,
marginRight: 10,
},
roundButtonIcon: {
textAlign: "center",
},
fromMe: {
alignSelf: "flex-end",
},
fromYou: {
alignSelf: "flex-start",
},
myChat: {
textAlign: "left",
fontSize: 18,
color: "white",
},
yourChat: {
textAlign: "right",
fontSize: 18,
color: "white",
},
myChatContainer: {
backgroundColor: colors.MYCHATCOLOR,
paddingRight: 5,
paddingLeft: 15,
paddingTop: 10,
paddingBottom: 10,
borderColor: "white",
borderWidth: 1.5,
borderTopLeftRadius: 15,
borderBottomRightRadius: 15,
borderBottomLeftRadius: 15,
marginTop: 20,
},
yourChatContainer: {
backgroundColor: colors.YOURCHATCOLOR,
paddingRight: 15,
paddingLeft: 9,
paddingTop: 10,
paddingBottom: 10,
borderColor: "white",
borderWidth: 1.5,
borderTopRightRadius: 15,
borderBottomRightRadius: 15,
borderBottomLeftRadius: 15,
},
yourUsername: {
color: "white",
fontSize: 20,
marginBottom: 10,
marginTop: 10,
},
});
when the chatscreen loaded all the messages from backend loaded just fine
when i send a new chat message all the array was replaced with just one message
来源:https://stackoverflow.com/questions/64087248/strange-react-native-state-behaviour-while-using-socket-io