React JS socket.io-client opens multiple connections - node.js

I have a simple React JS app connected to a socket io server. Whenever I open the app in the browser, the client sends new connection request to the server every 5 seconds.
server:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server);
io.on('connection', (socket) => {
console.log('socket id:', socket.id);
})
server.listen(3001, () => {
console.log('Listening on port 3001');
})
client:
import React from 'react';
import io from 'socket.io-client';
const socket = io('http://localhost:3001');
const App = () => {
return (
<div>Hi there!</div>
);
}
export default App;
logs on the server:
socket id: ByXQEMgeVaQ5AGw1AAAA
socket id: 8LzNQsyeYq7GSEvqAAAB
socket id: bbuYEs4kKzjxXuBsAAAC
socket id: vwprv4hnJbRlStG4AAAD
I suspect there could be something wrong on my laptop, cause I don't see anything wrong in the code, any ideas?
Thanks in advance

I would recommend calling connect inside a useEffect and return the disconnect method to be called when the component dismounts.
const [socket, setSocket] = useState(null)
useEffect(() => {
const newSocket = io('http://localhost:3001')
setSocket(newSocket)
return socket.disconnect()
}, [])

Can you try to wrap the client side socket creation in a useEffect that only runs once? I'm curious to see if the behavior still appears.
import React from 'react';
import io from 'socket.io-client';
const socket = io('http://localhost:3001');
const App = () => {
useEffect(() => {
const socket = io('http://localhost:3001');
}, [])
return (
<div>Hi there!</div>
);
}
export default App;

Actually I just found the root cause, I had a mismatch between my client version and my server version. I updated the client version to v4 and now it is working

Related

Expo react-native will not connect to socketio(Android and iOS)

im trying to connect to socketio with expo and reacti-native for ios(connection through expo app tunnel connection) and android with emulator, when i tried to connect with these the socket won't connect but if i open the expo app in broswer socket connection works but on mobile emulators not.. what can i do?
code for client
import { StatusBar } from 'expo-status-bar';
import React, { useEffect, useState } from 'react';
const io = require('socket.io-client');
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import useCachedResources from './hooks/useCachedResources';
import Navigation from './navigation';
import { Provider } from 'react-redux';
import { store } from './redux/store'
export default function App() {
const isLoadingComplete = useCachedResources();
const [data, setData] = useState(null)
useEffect(() => {
const socket = io('http://localhost:5000', {
});
socket.on("ping", (data: any) => {
setData(data)
})
}, [])
console.log(data)
if (!isLoadingComplete) {
return null;
} else {
return (
<Provider store={store}>
<SafeAreaProvider>
<StatusBar style="dark" />
<Navigation />
</SafeAreaProvider>
</Provider>
);
}
}
code for server
require("dotenv").config();
const express = require("express");
const http = require("http");
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const PORT = process.env.PORT || 5000;
const io = socketIO(server);
io.on('connection', socket => {
console.log('client connected on websocket');
setInterval(() => {
io.emit('ping', { data: (new Date()) / 1 });
}, 1000);
});
server.listen(PORT, () => console.log(`Server Running on Port: http://localhost:${PORT}`));
Make sure you are connecting with the right versions in each part, client and server.
Review https://socket.io/docs/v3/client-installation/index.html to make sure you have the right versions. I went through the source code and make sure mine was setup right and couldn't figure out why it wouldn't run.
I had a 4.0.1 of the socket.io-client installed in my react native expo app but only had 2.1.1 socket.io installed in the server. Once I upgraded to 4 on the server everything worked.
Also on the client side change
const socket = io('http://localhost:5000', {});
to
const socket = io('http://localhost:5000', {transports: ['websocket']});

react client: websocket.js:83 WebSocket connection to 'ws://localhost:3009/socket.io/?EIO=4&transport=websocket' failed:

i have a node backend using socket io
first in app.js initialize te app
const express = require("express")
const app = express()
module.exports = {
app,
express
}
then in io.js, i create the socket server
const { app } = require("./app");
const http = require("http");
const socketio = require("socket.io");
const server = http.createServer(app);
const io = socketio(server);
module.exports = io;
then in the server.js first i import the app.js for api calls then i import io.js
require("dotenv").config();
const { app, express } = require("./app");
const logger = require("./logger");
const io = require("./io");
then i simply add emit listen code in the server.js
io.on("connection", (socket) => {
console.log("we have a new connection");
socket.on("disconnect", () => {
console.log("the socket disconnected");
});
socket.on("join", ({ user_id }, callback) => {
// const notification = getListNotifications(user_id);
// const popup = getUserPopup(user_id);
// socket.emit("nofication", { popup: popup.count, notification });
socket.emit("nofication", { popup: 3, notificaton: { a: 1 } });
socket.join(user.room);
callback();
});
then i run the server.js file in dev mode nodemon server.js
Then in react i simply use socket.io
import io from "socket.io-client";
useEffect(() => {
socket = io("ws://localhost:3009", {
"force new connection": true,
reconnectionAttempts: "Infinity",
timeout: 10000,
transports: ["websocket"],
});
return () => {
socket.disconnect();
};
}, []);
it gives me this error in browser console
the server node.js console is receiving https protocol
i find out in other answers that it maybe some protocol issue.
happy to learn from you. Thanks in advance
Happened to me that i was listening the server with app.listen which only recieves https protocol....but i have created a seperated ws server with the server variable which should listen to a port so that the server can receive ws connection...
better to use this library npm link will make work much easier...

ReactJS does not connect with NodeJS API using socket.io

I have an issue trying to connect a reactJS app with a nodeJS API using socket.io.
Here's API code :
const httpServer = require('http').createServer();
const io = require('socket.io')(httpServer);
httpServer.listen(8080, () => {
console.log('go to http://localhost:8080');
});
io.on('connection', socket => {
console.log('client connected');
});
And reactapp :
import React from "react";
import socketIOClient from "socket.io-client";
const ENDPOINT = "http://localhost:8080";
function App(){
const socket=socketIOClient.connect(ENDPOINT);
return(<p>Hello</p>);
}
export default App;
As you can see, it is a simple code but still it doesn't work.
The 'client connected' message from the API never shows up.
It looks like the react app can't connect to the port even if it's open or idk.
It may happen because of syntax in the react app side. Can you try this one in the function?
function App(){
let socket = io(ENDPOINT, {
transports: ["websocket"],
});
console.log("Connecting...");
socket.on("connect", () => console.log("Connected!"));
}
or you can define socket outside of the function.

Socket.io v3.0.4 not connecting, v2.3 does work

Summary
I have basic sample code which works in socket.io 2.3 which does not work in socket.io 3.0, I want to understand what I need to change.
Full Description
I have a node.js / react project and I wanted to use socket.io. To do this, I implemented the example code from this article, using socket.io v3.0.4, which follows.
Server side:
const http = require("http");
const socketIo = require("socket.io");
const port = process.env.PORT || 4001;
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server);
let interval;
io.on("connection", (socket) => {
console.log("New client connected");
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => getApiAndEmit(socket), 1000);
socket.on("disconnect", () => {
console.log("Client disconnected");
clearInterval(interval);
});
});
const getApiAndEmit = socket => {
const response = new Date();
// Emitting a new message. Will be consumed by the client
socket.emit("FromAPI", response);
};
server.listen(port, () => console.log(`Listening on port ${port}`));
Client Side:
import React, { useState, useEffect } from "react";
import socketIOClient from "socket.io-client";
const ENDPOINT = "http://127.0.0.1:4001";
function App() {
const [response, setResponse] = useState("");
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on("FromAPI", data => {
setResponse(data);
});
}, []);
return (
<p>
It's <time dateTime={response}>{response}</time>
</p>
);
}
export default App;
on the server, I was receiving the error
socket.io:client client close with reason ping timeout
which led me to this article, which implied a version issue.
Based on that, I've attempted a few things, but specifically, I was running socket.io and socket.io-client both version 3.0.4. I uninstalled and reinstalled v 2.3.0/2.3.1. It now works flawlessly.
So my question is: what do I need to change to make this work with the more recent version of socket.io.

How to connect and disconnect socket depending on specific routes in react

I am trying to implement an online multiplayer game using socketio. So far, I have created a couple of routes including a home, login, and game page with their respective components. Here is my server side code for the socket.
const express = require('express');
const connectDB = require('./config/db');
const http = require('http');
const socketio = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
//socket logic
io.on('connect', socket => {
console.log('User Connected');
console.log(socket.id);
socket.on('disconnect', () => {
console.log('User Disconnected');
});
});
When a socket connects, it should log "User Connected" and the id, and when it disconnects it should log "User Disconnected". On the frontend, I included the socket logic within the board component which renders on the route of "/board?room=id" for some room id. When this component is mounted, the socket connects. However, after I leave the page, the socket doesn't disconnect. Furthermore, when I go back to the board page, the console outputs "User Connected" again with a different id. Does this mean that there are multiple socket connections, and is there a way to disconnect the socket once I leave the page? Here is the client side socket code:
import React, { Fragment, useState, useEffect } from 'react';
import io from 'socket.io-client';
import { connect } from 'react-redux';
import { leaveRoom } from '../../../actions/game';
import { Redirect } from 'react-router-dom';
import queryString from 'query-string';
let socket;
const Board = ({ game, auth, leaveRoom, location }) => {
const ENDPOINT = 'http://localhost:5000';
//room info
const [room, setRoom] = useState('');
//determines redirect
const [exit, setExit] = useState(false);
useEffect(() => {
const { room } = queryString.parse(location.search);
socket = io(ENDPOINT);
setRoom(room);
//When to redirect
if (
((!game.inGame || room !== game.room._id) && !game.loading) ||
!game.room
) {
leaveRoom();
setExit(true);
}
}, [ENDPOINT, location.search]);
if (exit) {
return <Redirect to='/menu' />;
}
Does this mean that there are multiple socket connections,
Yes, if you call io() with same namespace multiple times, it will creates multiple connections. check https://socket.io/docs/client-api/
To disconnect when unmount, you need to return a cleanup function in useEffect.
useEffect(()=>{
let socket = io(ENDPOINT);
return ()=>{
socket.disconnect();
}
});
check https://reactjs.org/docs/hooks-effect.html#recap

Resources