首页 > 解决方案 > 在 socket.io 事件上更新组件 - ReactJS,Socket.io

问题描述

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

插座:

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;

标签: javascriptreactjssocketseventschat

解决方案


您应该在安装组件时连接到套接字,然后附加消息处理程序。
但问题是,如果您在 useEffect 中执行此操作,您的处理程序希望看到状态更改(您的消息数组将始终为空,因为在初始状态下。那是因为 useEffect 有空数组作为第二个参数。这就像鸡蛋问题。你不能使用正常的 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>
}

推荐阅读