gpt4 book ai didi

javascript - Socket.io 连接完好无损,但从不卸载的 React 组件在页面导航后变得对套接字事件无响应

转载 作者:行者123 更新时间:2023-12-05 03:28:31 24 4
gpt4 key购买 nike

设置:

  • React-router-dom 中的 Socket.io
  • 通过useContext传递给子组件的Socket实例
  • 使用 Express 构建后端

问题:
Navbar 监听套接字事件以更新未读消息的计数器。一切正常,直到用户导航到不同的页面。一旦发生导航,即使连接完好无损,导航栏中的套接字(永远不会卸载)也不会响应服务器发出的 future 事件。

预期行为:
导航栏套接字在页面导航后仍然响应服务器发出的信号。

观察:
即使导航栏套接字没有响应,应用程序中使用套接字的其他区域仍然可以正常工作。刷新页面时导航栏套接字再次响应,但在页面导航后重复出现相同的问题。导航栏是唯一在发生导航时不会卸载的组件,而安装在导航上的组件是通过 useContext 使用套接字实例加载的。

据我所知,连接永远不会中断(断开事件永远不会在服务器端触发)并且新安装的组件可以发出一个事件,服务器响应,并向新组件响应的客户端发出响应,同时导航栏没有。

其他注意事项:
这是我问过的第一个问题,如果问题格式不正确,我提前道歉。代码显然已简化,以省略似乎不会影响问题的区域。省略了服务器端代码,因为它似乎可以毫无问题地接收和发出事件。

//App.js

const App = () => {
const socket = useRef(io('path'));

return (
<SocketContext.Provider value={socket.current}>
<BrowserRouter>
<Nav />
<Switch>
<Route path='/messages' component={Messages} />
<Route path='/' component={Home} />
<!-- Other routes -->
</Switch>
</BrowserRouter>
</SocketContext.Provider>
)
}
//Nav.js

const Nav = () => {
const socket = useContext(SocketContext);

const [newMsgCount, setNewMsgCount] = useState(0);

useEffect(() => {
socket.emit('get new msg count');

socket.on('new msg count', (count) => setNewMsgCount(count));

socket.on('new msg received', () => setNewMsgCount(prev => prev + 1));

socket.on('marked as read', () => setNewMsgCount(prev => prev - 1));

return () => {
socket.off('new msg count');
socket.off('new msg received');
socket.off('marked as read');
}
}, [socket]);

return (
//Omitted for brevity
)
}
//Messages.js

const Messages = () => {
const socket = useContext(SocketContext);

const [msgs, setMsgs] = useState([]);
const [newMsg, setNewMsg] = useState({ to: '', body: '' });

useEffect(() => {
socket.emit('get all msgs');

socket.on('all msgs', (data) => setMsgs(data));

socket.on('new msg received', (data) => setMsgs(prev => ([...prev, data])));

return () => {
socket.off('all msgs');
socket.off('received new msg');
}
}, [socket]);

const send = () => socket.emit('new msg', newMsg);

return (
<div>
<!-- Omitted for brevity -->
<form onSubmit={send}>
<!-- Omitted for brevity -->
<button>Send</button>
</form>
</div>
)
}

最佳答案

问题

您没有正确断开/取消订阅套接字。 socket.off 接受两个参数,第二个是您要断开连接/取消监听/取消订阅事件的监听器回调。

socket.off(eventName, listener)

Removes the specified listener from the listener array for the eventnamed eventName.

const listener = (...args) => {
console.log(args);
}

socket.on("details", listener);

// and then later...
socket.off("details", listener);

解决方案

将监听器重构为可传递给 socket.on socket.off 的独立函数>.

导航.js

const Nav = () => {
const socket = useContext(SocketContext);

const [newMsgCount, setNewMsgCount] = useState(0);

useEffect(() => {
socket.emit('get new msg count');

const incrementCount = () => setNewMsgCount(prev => prev + 1);
const decrementCount = () => setNewMsgCount(prev => prev - 1);

socket.on('new msg count', setNewMsgCount);
socket.on('new msg received', incrementCount);
socket.on('marked as read', decrementCount);

return () => {
socket.off('new msg count', setNewMsgCount);
socket.off('new msg received', incrementCount);
socket.off('marked as read', decrementCount);
}
}, [socket]);

...
}

消息.js

const Messages = () => {
const socket = useContext(SocketContext);

const [msgs, setMsgs] = useState([]);
const [newMsg, setNewMsg] = useState({ to: '', body: '' });

useEffect(() => {
socket.emit('get all msgs');

const messageRecdHandler = (data) => setMsgs(prev => ([...prev, data]));

socket.on('all msgs', setMsgs);
socket.on('new msg received', messageRecdHandler);

return () => {
socket.off('all msgs', setMsgs);
socket.off('received new msg', messageRecdHandler);
}
}, [socket]);

const send = () => socket.emit('new msg', newMsg);

...
}

我同意 Silven 的观点,即套接字可能应该从父 React 组件代码中移出。将其实例化一次并将其设置为单例的上下文值。

关于javascript - Socket.io 连接完好无损,但从不卸载的 React 组件在页面导航后变得对套接字事件无响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71239032/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com