当用户不在聊天中时如何显示发送的最后一条消息?

Posted

技术标签:

【中文标题】当用户不在聊天中时如何显示发送的最后一条消息?【英文标题】:How to display the lastmessage sent when user is not inside the chat? 【发布时间】:2021-04-17 07:48:34 【问题描述】:

我目前有 2 个屏幕,一个是包含我参与的所有聊天的所有消息屏幕,另一个是实际聊天本身的聊天屏幕。

在我的聊天屏幕中,我成功实现了套接字,因此当两个用户同时在聊天屏幕上时,消息就会实时交换。

我的问题:

如果用户 1 在所有消息屏幕上,而用户 2 在聊天中。并且用户 2 向用户 1 发送消息,用户 1 的屏幕不会自动更新消息发送到的对话的最后一条消息,我需要滚动刷新或从一个页面导航到另一个页面才能显示.

有人建议我在 allmessages 屏幕上使用套接字来监听任何事件变化。

在我的数据库中,我有一个对话表和一个消息表。会话表有以下字段:id、user1、user2、postId、lastMessage。 messages 表有以下字段:id、senderID、receiverID、conversationId、message。

客户

Chatscreen.js

useEffect(() => 
const newsocket =io.connect("IP:PORT")
setMessages(message.Messages)

newsocket.on('connect', msg => 
console.log(`user: $user.id has joined conversation $message.id`)
setSocket(newsocket)
newsocket.emit('subscribe', message.id);
 );

newsocket.on("send_message", (msg) => 
console.log("this is the chat messages:", msg);
setMessages(messages => messages.concat(msg))
);

return(()=>newsocket.close());

, []);

const onSend = (ConversationId,senderId,receiverId,message) => 
console.log("sent")
const to = (user.id===route.params.message.user1? 
route.params.message.user2:route.params.message.user1)
socket.emit('message',  to: to, from: user.id, message,ConversationId );
setText("")
messagesApi.sendMessage(ConversationId,senderId,receiverId,message);
;

allmessagesScreen.js

const [posts, setPosts] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const[page,setPage]=useState(0);
const [refreshing, setRefreshing] = useState(false);

const loadPosts = async () => 
setLoading(true);
const response = await messagesApi.getMessages();
setLoading(false);

if(refreshing) setRefreshing(false);

if (!response.ok) return setError(true);

setError(false);

setPosts(response.data)
;

useEffect(() => 
const unsubscribe = navigation.addListener('focus', () => 
loadPosts();
);
return unsubscribe;
, [navigation]);

return(

<FlatList
    data=posts
    keyExtractor=(post) => post.id.toString()
    renderItem=( item,index ) => (
      <MessagesList
      title=item.Post.title
        subTitle=item.Messages[0].message
        onPress=() => navigation.navigate(routes.CHAT,message:item,index)
      />
    )
    refreshing=refreshing
    onRefresh=() => 
      loadPosts()
    
  />

服务器

io.on('connection',(socket)=>
console.log('User '+socket.id+' connected')

socket.on('subscribe', (room)=> 
console.log('joining room', room);
socket.join(room);
);

socket.on('message', (data) => 
console.log(data)
console.log('sending room post',data.ConversationId)
io.sockets.in(data.ConversationId).emit('send_message',  message: 
data.message, receiverId: 
data.to,senderId:data.from,conversationId:data.ConversationId );
)
)

我尝试了以下操作,我的控制台日志正在打印,但功能仍然不起作用。

客户

Chatscreen.js

useEffect(() => 
const newsocket =io.connect("IP:PORT")
setMessages(message.Messages)

newsocket.on('connect', msg => 
console.log(`user: $user.id has joined conversation $message.id`)
setSocket(newsocket)
newsocket.emit('subscribe', message.id);
 );

newsocket.on("send_message", (msg) => 
console.log("this is the chat messages:", msg);
setMessages(messages => messages.concat(msg))
);

return(()=>newsocket.close());

, []);

const onSend = (ConversationId,senderId,receiverId,message) => 
console.log("sent")
const to = (user.id===route.params.message.user1? 
route.params.message.user2:route.params.message.user1)
socket.emit('message',  to: to, from: user.id, message,ConversationId );
setText("")
messagesApi.sendMessage(ConversationId,senderId,receiverId,message);
;

allmessagesScreen.js

const [posts, setPosts] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const[page,setPage]=useState(0);
const [refreshing, setRefreshing] = useState(false);

const loadPosts = async () => 
setLoading(true);
const response = await messagesApi.getMessages();
setLoading(false);

if(refreshing) setRefreshing(false);

if (!response.ok) return setError(true);

setError(false);

setPosts(response.data)
;

  useEffect(() => 
  const newsocket =io.connect("http://ip:port")
  loadPosts()

   newsocket.on('connect', msg => 
    console.log(`waiting for user: $user.id to join a conversation`) //this gets printed 
    setSocket(newsocket)
    newsocket.emit('waiting', user.id);
   );

 newsocket.on("send_message", (msg) => 
  console.log("this is the last message:", msg); //this doesnt get printed 
);
   , []);

return(

<FlatList
    data=posts
    keyExtractor=(post) => post.id.toString()
    renderItem=( item,index ) => (
      <MessagesList
      title=item.Post.title
        subTitle=item.Messages[0].message
        onPress=() => navigation.navigate(routes.CHAT,message:item,index)
      />
    )
    refreshing=refreshing
    onRefresh=() => 
      loadPosts()
    
  />

服务器

io.on('connection',(socket)=>
console.log('User '+socket.id+' connected')//this gets printed 

socket.on('subscribe', (room)=> 
console.log('joining room', room);//this gets printed 
socket.join(room);
);

socket.on('message', (data) => 

console.log(data) //this gets printed 
console.log('sending room post',data.ConversationId) //this gets printed 
io.sockets.in(data.ConversationId).emit('send_message',  message: 
data.message, receiverId: 
data.to,senderId:data.from,conversationId:data.ConversationId ); 
)

socket.on('waiting', (user)=> 
console.log('user', user, 'is waiting.');//this gets printed 
);

)

【问题讨论】:

console.log('User '+socket.id+' connected') 被触发了吗? @AvivLo 在服务器端是的,当我重新加载我的应用程序并转到所有消息屏幕时,我得到User S1CTDD6euE593ZYaAAB1 connecteduser 53 is waiting.,在客户端我得到waiting for user: 53 to join a conversation 你熟悉事件发射器吗?后端的每个emit 都应该在客户端有一个对应的on,反之亦然。 @AvivLo 嗨,很抱歉打扰你,但我已经更新了问题,如果你可以请看一下 @kd12345 我建议不要在组件中创建连接,而是使用 redux-sagas 来管理后台 websocket 连接。 【参考方案1】:

我昨天也遇到了同样的问题。但现在它已经修复了。这个应该可以的

import React,  useEffect, useState, useRef  from 'react'
import socket from 'socket.io-client'

const Chatbox = () => 
  const [chats, setChats] = useState([])
  const [message, setMessage] = useState('')
  const socketClientRef = useRef()

  useEffect(() => 
    const client = socket("http://localhost:3002");
    client.on("connect", () => 
      console.log('connected')
    )
    client.on("disconnect", () => 
      console.log('diconnected')
    );
    client.on("chat", message => 
      setChats(prevChats => [...prevChats, message])
      // INSTEAD OF:
      // setChats([...chats, message])
    );
    socketClientRef.current = client
    return () => 
      client.removeAllListeners()
    
  , [])

  const handleSend = async () => 
    socketClientRef.current.emit('chat', 
      room: `event-$eventId`,
      message
    )
    setMessage('')
  


  return (
    <div>
      <div>
        <h1>Messages</h1>
        chats.map(chat => (
          <div>chat</div>
        ))
      </div>
      <div>
        <input value=message onChange=e => setMessage(e.target.value) />
        <button onClick=handleSend>Send</button>
      </div>
    </div>
  )

【讨论】:

您好,感谢您回复我。这是用户准确消息的聊天屏幕本身吗?如果是的话,这对我有用,我的问题是例如。如果 user1 在聊天中并且 user2 在包含所有聊天的屏幕上,如果用户 1 发送消息,则发送的最后一条消息不会自动更新给 user2。你明白我的问题了吗?【参考方案2】:

:如果用户 1 在所有消息屏幕上,而用户 2 在聊天中。并且用户 2 向用户 1 发送消息,用户 1 的屏幕不会自动更新为消息发送到的会话的最后一条消息

user2 发送消息时,发出带有socketiduser1 的事件。在on 事件的帮助下,user1 将收到该消息。只要user1 正在监听事件,user1 在哪个页面上都没有关系。

只需确保发送消息的元数据,以便您能够在客户端区分和处理消息。

【讨论】:

如果两个用户都在聊天中,我的代码可以正常工作并且消息会实时呈现。我的问题是如果 user2 在聊天中并且 user1 在所有聊天的屏幕上并且 user2 向 user1 发送消息,则所有聊天的屏幕都不会自动更新 当用户在所有聊天屏幕上时是否触发事件? 连接事件触发,但 allmessages 屏幕内的 send_message 事件没有 嘿 Abhishek,你能帮我解决一下真的卡住了吗,我的老板今天要我解决这个问题。 当然,只需分享您的回购链接即可。我会努力解决的。

以上是关于当用户不在聊天中时如何显示发送的最后一条消息?的主要内容,如果未能解决你的问题,请参考以下文章

Zapier Slack 私人频道:仅当用户在频道中时才发送消息

不在 View Hierarchy 中时重新加载 UITableView/(一般是控制器)

java websocket上线后如何发送离线用户的消息?

DiscordJS 13用户嵌入显示在特定频道发送的最后一条消息

如何找到特定用户 discordjs 的最后发送消息

如何从 itemBuilder 访问查询?