Setup:
- Socket.io in React with react-router-dom
- Socket instance passed to child components via useContext
- Backend built using Express
Problem:
Navbar listens for socket events to update counters for unread messages. Everything works fine until user navigates to a different page. Once a navigation occurs, the socket in navbar (which never unmounts) is unresponsive to future events being emitted from the server even though the connection is intact.
Expected behaviour:
Navbar socket remains responsive to emits from server after page navigation.
Observation:
Other areas of the app where socket is utilized remains functional even while navbar socket is unresponsive. The navbar socket becomes responsive again when page is refreshed but the same problem repeats after page navigation. The navbar is the only component that doesn't unmount when a navigation occurs while components mounted on navigation is loaded with the socket instance via useContext.
As far as I can see, connection is never broken (disconnect event never fires on server-side) and the newly mounted component can emit an event, server responds, and emits a response back to client where the new component responds while the navbar doesn't.
Other notes:
This is the first question I've ever asked so my apologies in advance if the question is poorly formatted. The code is obviously simplified to leave out areas where it seems to not affect the problem. The server-side code is omitted because it seems to receive and emit events without any problems.
//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>
)
}