Reputation: 690
After several hours of messing around with socket.io, I finally got it working, but it doesn't work as the docs describe. At this point, I'm just wondering what is going on here..
server.js
const server = require('http').createServer(app);
const io = require('socket.io')(server);
const PORT = process.env.PORT || 5000;
server.listen(PORT);
// this works as expected
// io.on('connection', socket => {
// console.log('connect', socket.id);
// socket.emit('test', 'emit from server');
// });
// Make io accessible to our router
app.use(function (req, res, next) {
req.io = io;
next();
});
app.use('/api/posts', require('./routes/api/posts'));
/api/posts.js
router.post('/', async (req, res) => {
const user = await User.findById(req.user.id)
// this does not work
// req.io.on('connection', socket => {
// socket.emit('123', "foo: bar");
// });
// but this does...
req.io.emit(user.id, "foo: bar");
})
client
const myComponent = ({
auth: { user },
notifications: {
notifications,
activeNotifications,
loading: notification_loading,
}}) =>{
const [socketData, setSocketData] = useState(false);
useEffect(() => {
if (!notification_loading) {
const socket = io();
socket.on('connect', () => {
console.log('LINE2: 67 _connect ', 'connect');
});
socket.on(user.id, function (data) {
setSocketData(data);
});
}
}, [notification_loading]);
useEffect(() => {
socketData &&
pollNotifications(
{
newestIndex: notifications[0] ? notifications[0].date : 0,
},
socketData
);
setSocketData(false);
return () => {};
}, [socketData]);
return (<span> blah blah </span>)
}
I stumbled onto some posts of people using it with just io.emit
, so I tried it and it worked, but does anyone know why?
Upvotes: 0
Views: 1221
Reputation: 708116
You have to think through the lifetime of a browser page and the sequence of events with a socket.io connection to understand why there's a problem with the version of the code that doesn't work.
Let's assume you have a web page that makes a socket.io connection when the page is first loaded into the browser.
If, sometime after that page is loaded, that page makes an Ajax call to do a POST to the / route, then doing req.io.on('connection', socket => { ....})
will install an event handler for future connection
events that will happen for other pages and, in fact, those event handlers will accumulate with lots of duplicates. The page that has make the Ajax call is already connected to socket.io so that page itself will not generate another connect
message and thus you will never see the results of that event handler in the page that made the ajax call.
If, sometime after that page is loaded, that page makes a form POST to the /
route, then it will indeed install yet another handler for the connect
event just like before and again, they will accumulate with lots of duplicate event handlers over time. Your POST handler would presumably send a response and that would cause the browser to load a NEW web page. When that web page loads and then makes its socket.io connection, you probably would get that 123
event sent to it, but you still can't code it this way because of the build-up of event handlers.
What you need to remember is that something like this:
// this does not work
req.io.on('connection', socket => {
socket.emit('123', "foo: bar");
});
is a global handler for all socket.io connect
events from all clients. It does NOT pertain to just the client that is making the current POST request. Thus, you never want to install global event handlers within routes because every single time that route is hit by any client, you will add yet another duplicate event handler and they will pile up indefinitely.
There are likely other ways to solve whatever problem you're trying to solve, but frankly, we'd need to know what the actual problem is in order to suggest a better way to solve it. Here you are only describing the problem with your solution and not describing what the actual problem is. Since, this is the wrong approach, we need to go back several steps to what the fundamental problem is so we can suggest a different approach.
In many cases, what people are trying to do is to "emit to a socket.io connection that corresponds to the client that is making the current http request (if there is one)". That is usually done by getting the socket.id
from an http cookie and then using that socket.id to find the right socket to emit to. This is generally only possible if the http request comes from an Ajax call from an already established web page. If the http request comes from the browser attempting to fetch and load a new web page, then that page does not yet have an established socket.io connection so you can't yet emit to it.
Upvotes: 1