在 socket.io 事件上更新组件 - ReactJS,Socket.io

Update component on socket.io event - ReactJS, Socket.io

我有一个使用 Socket.io 的 React 聊天应用程序。我可以从不同的源发送消息,但不能更新连接到套接字的每个源。我试着这样做 componentDidUpdate,使用 refs 和 e.t.c 来保持套接字,但没有任何效果。

套接字:

const io = require('socket.io').listen(3002);
const jwt = require('jsonwebtoken');

const messages = [];

io.use((socket, next) => {
  if (socket.handshake.query && socket.handshake.query.token) {
    jwt.verify(
      socket.handshake.query.token,
      '4-8-15-16-23-42',
      (err, decoded) => {
        if (err) return next(new Error('Authentication error'));
        socket.decoded = decoded;
        next();
      }
    );
  } else {
    next(new Error('Authentication error'));
  }
}).on('connection', socket => {
  socket.emit('connected', {
    user: socket.decoded.username
  });

  socket.on('newMessage', message => {
    messages.push(message);
    socket.emit('messages', messages);
  });
});

客户:

import { useState, useEffect } from 'react';
import io from 'socket.io-client';

const token = sessionStorage.getItem('token');
const socket = io('http://localhost:3002', {
  query: { token }
});

const Chat = () => {
  const [user, setUser] = useState('');
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState('');

  useEffect(() => {
    socket.on('connected', msg => {
      setUser(msg.user);
    });
  }, []);

  const inputChangeHandler = e => setInput(e.target.value);

  const sendMessage = () => {
    socket.emit('newMessage', `${user}: ${input}`);
    socket.on('messages', newMessages => setMessages(newMessages));
    setInput('');
  };

  return (
    <div>
      <div id="message-container">
        <div>Greetings {user}!!!</div>
        {messages.map((message, index) => (
          <div key={index}>{message}</div>
        ))}
      </div>
      <input value={input} onChange={e => inputChangeHandler(e)} />
      <button onClick={sendMessage}>Send</button>
    </div>
  );
};

export default Chat;

你应该在挂载组件时连接到套接字,然后附加消息处理程序。
但问题是,如果你在 useEffect 中这样做,你的处理程序希望看到状态变化(你的消息数组将始终为空,就像在初始状态一样。那是因为 useEffect 有空数组作为第二个参数。这有点像 chicken-egg 问题. 你不能使用正常的 useState 或 useReducer 所以...

解决方法如下:

首先删除这个:

    socket.on('messages', newMessages => setMessages(newMessages));

来自 sendMessage 函数。

我们需要一些额外的包裹。

yarn add immer use-immer
import React, {useEffect, useRef } from "react";
import io from 'socket.io-client';
import { useImmer } from "use-immer";

const Chat = () => {

  const [messages, setMessages] = useImmer({});

  useEffect(() => {

    const serverAddress = "https://my-chat-server";
    const socket = io( serverAddress,{
      transports: ['websocket']
    });

    socket.on("connect", () => {
      console.log("Connected");
      socketRef.current = socket;
    });

    socket.on("message", msg => {

      setMessages(msgs => {

        return msgs.concat(msg);

      });

    });


  },[setMessages]);

   return <div>Here you know what to do :)</div>
}