我目前有一个 react native 应用程序,nodejs express Sequelize 作为我的后端,postgres 作为我的数据库。
因此,在每个帖子旁边的帖子屏幕上,我有一个文本输入和一个按钮,当前用户可以在其中向帖子的用户发送初始消息。按下按钮后,这两个用户之间关于此帖子的对话将在我的数据库中创建并存储在我的对话表中,发送的消息的条目也存储在我的消息表中。
我已经实现了这两个用户之间的双向通信。但我的问题是我需要刷新应用程序才能向用户当前用户显示发送的消息并向接收用户显示收到的消息。
我已经研究了一段时间并试图了解如何使用 socket.io 实现此功能,但无处可去。
客户端
这是我的聊天屏幕
function ChatScreen({route,navigation}) {
const message = route.params.message;
const [messages, setMessages] = useState(message.Messages);
const [text, setText] = useState('');
const { user } = useAuth();
const [socket, setSocket] = useState(null);
useEffect(() => {
const newsocket =io.connect(socketurl)
setMessages(messages);
newsocket.on('connection', msg => {
console.log('i have joined')
setMessages(messages=>messages.concat(msg))
setSocket(newsocket)
})
return()=>newsocket.close;
}, []);
const updateText=(text)=>{
setText(text);
}
const onSend = (ConversationId,senderId,receiverId,message) => {
console.log("sent")
messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
setText("")
socket.emit('message', { to: (user.id===route.params.message.user1 ?
route.params.message.user2 : route.params.message.user1), from:
user.id, message,ConversationId });
};
return(
<Text>{user.id === message.Recipient.id ?
message.Creator.name:message.Recipient.name}</Text>
<KeyboardAvoidingView
style={{
display: "flex",
flex: 1,
}}
behavior={Platform.OS === "ios" ? "padding" : null}
keyboardVerticalOffset={Platform.OS === "ios" ? 25 : 0}
>
<FlatList
inverted
data={message.Messages}
keyExtractor={(message) => message.id.toString()}
renderItem={({item,index})=>(
<MessageBubble
text={item.message}
mine={item.senderId !== user.id}
/>
)}/>
<View style={styles.messageBoxContainer}>
<TextInput
style={styles.messageBox}
placeholder="Message..."
multiline
clearButtonMode="while-editing"
onChangeText={updateText}
value={text}
autoCorrect={false}
/>
<TouchableOpacity onPress={onSend}>
<Text style={styles.send}>Send</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
服务器端索引.js
const express = require("express");
const app = express();
const http = require("http");
const socketio = require("socket.io")
const server=http.createServer(app);
const io =socketio(server)
io.on("connection", socket => {
socket.on('message', (data) => {
socket.join(data.ConversationId);
io.sockets.in(data.to).emit('send_message', { message: data.message,
to: data.to });
});
});
const port = process.env.PORT || config.get("port");
server.listen(port, function () {
console.log(`Server started on port ${port}...`);
});
目前,当我发送消息时,消息会存储在我的数据库中,但我的聊天不会立即更新(即不是实时更新),我需要刷新我的应用程序并显示消息。有人可以帮助我并检查我当前拥有的套接字的实现是否正确,如果正确,我如何立即呈现我的平面列表?
更新
我认为我的 useEffect 有问题,因为当我打开聊天时,我没有在控制台中收到“我已加入”:
useEffect(() => {
setMessages(messages);
socket.on('connect', msg => {
console.log('i have joined')
setMessages(messages=>messages.concat(msg))
})
}, []);
最佳答案
您当前在每次状态更改时创建新连接.. const socket =io.connect(socketurl)
您有一个 useEffect 回调,这将是放置连接逻辑的合乎逻辑的位置,目前您只监听一次连接,但创建多个连接,因此永远不会在这些新连接上调用您的 'connection' 事件。但是无论如何你只想连接一次,所以我们只需要将连接逻辑也放在 useEffect 中,而不仅仅是连接事件。
因为连接到套接字是异步的,所以您需要在渲染之前等待连接。所以我们可以做的是将套接字存储在状态中,当我们获得连接集套接字状态时,这将使用现在有效的套接字触发重新渲染。
例如。
const [socket, setSocket] = useState(null);
...
useEffect(() => {
const socket = io.connect(socketurl)
setMessages(messages);
newsocket.on('connect', msg => { //connect not connection
console.log('i have joined')
setMessages(messages=>messages.concat(msg));
setSocket(newSocket);
});
//might make sense to close the socket too,
//otherwise a memory leak.
return () => newSocket.close();
}, [route, navigation]);
if (!socket) {
//we don't have a socket yet,
return "loading..";
} else {
// we have a socket,
const onSend = (ConversationId,senderId,receiverId,message) => {...
....
// now render..
return (
<Text>{.........
关于node.js - 使用 socket.io react 本地一对一对话,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65277256/