在 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>
}
我有一个使用 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>
}