【问题标题】:React native: Flatlist does not update instantly when i send a messageReact native:当我发送消息时,Flatlist 不会立即更新
【发布时间】:2021-03-27 05:48:31
【问题描述】:

我刚刚在我的 react native 和 nodejs 项目中设置了我的套接字,但我的平面列表在发送消息时仍然没有立即更新,我需要刷新应用程序才能更新。

我认为通过使用套接字这将起作用,但它仍然不起作用。每当我用户打开聊天时,我都会得到例如。 user: 1 在控制台中加入了会话 1,这表明套接字正在工作。

客户端

function ChatScreen({route,navigation}) {
const message = route.params.message;

const [messages, setMessages] = useState(message.Messages);
const [text, setText] = useState('');
const [socket, setSocket] = useState(null);
const { user } = useAuth();

const index = route.params.index;
const updateView = route.params.updateView;

useEffect(() => {
const newsocket =io.connect(socketURL)
setMessages(messages);
newsocket.on('connect', msg => {
    console.log(`user: ${user.id} has joined conversation ${message.id}`)
    setMessages(messages=>messages.concat(msg))
    setSocket(newsocket)
 });
 return()=>newsocket.close;
 }, []);

const onSend = (ConversationId,senderId,receiverId,message) => {

messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
setText("")

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 });
};

const updateText=(text)=>{
setText(text);
}

return (
    <FlatList
    inverted
    data={message.Messages}
    keyExtractor={(message) => message.id.toString()}
    renderItem={({item,index})=>(
        <>
        <Text>
         {moment(item.createdAt).fromNow()}
         </Text>
        <MessageBubble
        text={item.message}
        mine={item.senderId !== user.id}
        />
         </>
    )}      
    />
    <View style={styles.messageBoxContainer}>
        <TextInput 
        onChangeText={updateText} 
        value={text} 
        />
        <TouchableOpacity 
          onPress={()=>{onSend(message.id,user.id,(user.id===message.user1? 
          message.user2:message.user1),text)}}>
        </TouchableOpacity>
    </View>
);
}

服务器端

const express = require("express");
const app = express();
const http = require("http");
const socket = require("socket.io")
const server=http.createServer(app);
const io =socket(server)

io.on('connection', (socket) => {
console.log("connected")
socket.on('message', (data) => {
console.log(data)
  socket.join(data.ConversationId);
  io.sockets.in(data.to).emit('send_message', { message: 
  data.message, to: data.to });
  });
  });

更新

客户端

  const message = route.params.message;
  const [messages, setMessages] = useState([]);
  const [text, setText] = useState('');
  const [socket, setSocket] = useState(null);
  const { user } = useAuth();

  useEffect(() => {
  const newsocket =io.connect("http://192.168.1.103:9000")
  newsocket.on('connect', msg => {
  console.log(`user: ${user.id} has joined conversation 
  ${message.id}`)
  setSocket(newsocket)
  setMessages(message.Messages)
  });

  newsocket.on("send_message", (msg) => {
  console.log("this is the chat message:", msg);
  setMessages([ { ...message.Messages },...messages]);
  });

  return()=>newsocket.close;
  }, []);

  const onSend = (ConversationId,senderId,receiverId,message) => {
  console.log("sent")
messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
setText("")
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 });
  };

 const updateText=(text)=>{
 setText(text);
 }

<FlatList
    inverted
    data={messages}
    keyExtractor={(message) => message.id.toString()}
    renderItem={({item,index})=>(
        <>
        <Text>
         {moment(item.createdAt).fromNow()}
         </Text>
        <MessageBubble
        text={item.message}
        mine={item.senderId !== user.id}
        />
         </>
    )}   
    bounces={false}  
    />
    <View style={styles.messageBoxContainer}>
        <TextInput 
        onChangeText={updateText} 
        value={text} 
        />
        <TouchableOpacity 
         onPress={()=>{
         onSend(
         message.id,
         user.id, 
         (user.id===message.user1?message.user2:message.user1),
         text
         )}}
         >
         <Text>Send</Text>
        </TouchableOpacity>
     </View>

服务器端

io.on('connection', (socket) => {
console.log("connected")
socket.on('message', (data) => {
console.log(data)
socket.emit('send_message', { message: data.message, receiverId: 
data.to,senderId:data.from,conversationId:data.ConversationId })
});
});

使用更新的代码,当我打开聊天时,我会得到

user: 43 has joined conversation 4 ---- on client side console
connected ---- on server side console

使用更新的代码,当我发送消息时,我得到了

this is the chat message: Object {
"conversationId": 25,
"message": "You",
"receiverId": 47,
"senderId": 43,
} --- in my client side console

{ to: 47, from: 43, message: 'You', ConversationId: 25 } ---- server 
side console

然后我得到一个错误

undefined is not an object (evaluating 'message.id.toString')

我认为我的问题是我没有正确发出消息 ID,因此我的平面列表不知道它。要获取消息 ID,我需要先将消息存储在 db 中

新更新

客户端

  const message = route.params.message;
  const [messages, setMessages] = useState([]);
  const [text, setText] = useState('');
  const [socket, setSocket] = useState(null);
  const { user } = useAuth();

  useEffect(() => {
  const newsocket =io.connect(socketURL)
  newsocket.on('connect', msg => {
  console.log(`user: ${user.id} has joined conversation 
  ${message.id}`)
  setSocket(newsocket)
  setMessages(message.Messages)
  });

  newsocket.on("send_message", (msg) => {
  console.log("this is the chat message:", msg);
  const data = [...messages]; 
  console.log(data)
  data.push(msg);
  setMessages(data); 
  });

  return(()=>newsocket.close());
  }, []);

  const onSend = (ConversationId,senderId,receiverId,message) => {
  console.log("sent")
messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
setText("")
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 });
  };

 const updateText=(text)=>{
 setText(text);
 }

<FlatList
    inverted
    data={messages}
    keyExtractor={(item,index)=>index.toString()}
    renderItem={({item,index})=>(
        <>
        <Text>
         {moment(item.createdAt).fromNow()}
         </Text>
        <MessageBubble
        text={item.message}
        mine={item.senderId !== user.id}
        />
         </>
    )}   
    bounces={false}  
    />
    <View style={styles.messageBoxContainer}>
        <TextInput 
        onChangeText={updateText} 
        value={text} 
        />
        <TouchableOpacity 
         onPress={()=>{
         onSend(
         message.id,
         user.id, 
         (user.id===message.user1?message.user2:message.user1),
         text
         )}}
         >
         <Text>Send</Text>
        </TouchableOpacity>
     </View>

服务器端

io.on('connection', (socket) => {
console.log("connected")
socket.on('message', (data) => {
console.log(data)
socket.emit('send_message', { message: data.message, receiverId: 
data.to,senderId:data.from,conversationId:data.ConversationId })
});
});

现在在我发送消息时使用新的更新代码,只有新消息会呈现给发送者,而没有先前的消息,并且接收者在聊天时不会收到任何内容。

【问题讨论】:

  • 您监听的唯一内容是连接,您还想监听消息,.. 例如。 newsocket.on('msg', =&gt; .....) 在这个事件中你可以调用setMessages,你的服务器端当然也需要发出这些新消息。
  • @Keith 我已经在我的服务器端为消息发送了一个套接字,我已将它添加到上面的代码中
  • 但是您没有在客户端监听套接字更新,是吗?从您的代码中,您只需侦听客户端上的连接。此外,您必须使用收到的每条消息更新状态/道具,但现在您从来自路由的message.Messages 获取数据。
  • @Konstantin 在我的客户端 onSend 函数中我使用 socket.emit 进行消息事件
  • Emitting 用于发送消息,socket.on(smth) 用于接收套接字消息。您在哪里收到它们?

标签: react-native


【解决方案1】:

因此,从您的回答中,我得到的印象是,为了使其正常工作,您需要大致执行以下操作:

  1. 在您的客户端,您必须有一个侦听更新的套接字:

socket.on('send_message', (e) =&gt; doSomethingWith(e));

  1. 一旦您的套接字监听更新,您就可以处理收到的信息。确保组件重新呈现并显示正确信息的最简单方法是使用状态。因此,在从套接字接收到消息后,您可以设置消息

setMessages(socketMessage)

  1. 然后您将messages 状态传递给您在Flatlist 中的data。我也会在 Flatlist 的 extraData 字段 also 中传递它。 如果你有 redux,你可能想把消息保存在那里,那么就不需要在组件中设置本地状态,你可以从 props 中获取它。

希望这会有所帮助,如果您有任何其他问题,请随时提出。

编辑 1:

我只是从你上面提到的解决方案中复制代码:

useEffect(() => {
    handleGetGroupMessage();
    let socket = io(socketUrl);
    socket.on("GroupChat", (msg) => {
      console.log("this is the chat messages", chatMessages);
      setChatMessages(chatMessages.concat(msg)); // this is the "doSomethingWith(e)"
    });
  }, []);

您通过套接字接收消息,然后必须对其进行处理。不使用redux?将其设置为本地状态或顶级上下文,无论适用于您的应用。

编辑 2: socket.on('connect', ...) 是一个标准的event,socket 可以理解。这不是你的信息,你需要把它分开。

【讨论】:

  • 您好,感谢您提供更详细的解释,我没有使用 redux。 doSomethingWith(e) 是什么意思?
  • @kd12345 在我的回答中添加了信息。
  • 嗨,我已经更新了我上面的代码,请检查我所做的是否正确
  • 我认为接收端是正确的,你必须确保你正在接收消息。如果你这样做了,那么你只需要改变你传递给 flatlist 的数据就可以了。
  • 我应该在哪里接收消息?我只是尝试发送一条消息,但在控制台中没有收到“这是聊天消息”。这是否意味着我的套接字不能在客户端工作?
【解决方案2】:

试试这个方法

<FlatList
    inverted
    data={messages}
    keyExtractor={(item,index) => index.toString()}
    extraData={messages} // add this    
    renderItem={({item,index})=>(...)} 


useEffect(() => {
  ...

  newsocket.on("send_message", (msg) => {
    console.log("this is the chat message:", msg);
    // setMessages([ { ...message.Messages },...messages]); // remove this

    // add this 
    const data = [...messages]; 
    data.push(msg);
    setMessages(data);      
  });

  ...
  }, []);

【讨论】:

  • 刚刚尝试过这个并得到错误 undefined is not an object (evalating 'message.id.toString')。
  • 当我 console.log(msg) 我得到 Object { "conversationId": 26, "message": "Hii", "receiverId": 47, "senderId": 43, } 丢失消息,因为它仍然需要存储在数据库中才能获得消息 ID
  • 更新keyExtractor 就像我更新了我的答案
  • 现在当我发送一条消息时,只显示新消息而不是整个消息列表
  • 现在它类似于我发现的这个问题,但是当我尝试解决方案时建议它不起作用stackoverflow.com/questions/64087248/…
猜你喜欢
  • 2017-12-07
  • 2022-08-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
相关资源
最近更新 更多