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
Related
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
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']});
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.
I'm getting a successful "A user has appeared!" connection message on the back-end. Be there seems to be no communication after the connect event.
Also, the front end keeps disconnecting and reconnecting. Is this bad?
Super socket-io novice here, just started learning tonight.
Thank you in advance for the help.
Node.JS/Express Backend:
const express = require('express')
const server = express();
const http = require('http').createServer(server);
const socketio = require('socket.io');
// ! Express --
server.use(require('cors')());
server.use(express.json());
server.get("/", (req, res) => {
res.status(200).json({
message: `You've hit the socket.io backend!`
})
})
// ! SocketIO
const io = socketio(http);
io.on('connect', socket => {
// ! Emit CheatSheet -> https://socket.io/docs/emit-cheatsheet/
// -> I believe `socket` referes to the open instance of a connection.
// -> This allows us to use functions such as:
// -> .on(eventName, cb(data)) | Use `on` when you are getting data FROM the front end.
// -> .emit(eventName, { data }) | Use `emit` when you are sending data TO the front end.
console.log(`A user has appeared!`)
socket.on("hello", data => console.log(data))
socket.on('disconnect', () => {
console.log(`A user has disappeared.`)
})
});
const PORT = process.env.PORT || 5000;
http.listen(PORT, () => console.log(`Server started on ${PORT}.`));
React Front-End (App.js):
import React, { useEffect, useState } from 'react'
// -> SocketIO
import io from 'socket.io-client';
let socket;
export default () => {
const ENDPOINT = process.env.ENDPOINT || 'http://--server-ip--/'
const [message, setMessage] = useState('Secret Message from the Front-End')
useEffect(() => {
socket = io(ENDPOINT, {
transports: ['websocket']
});
socket.emit('hello', "Hello from the front-end!")
}, [ENDPOINT]);
return (
<div>
<p>{ message }</p>
</div>
)
}
In your client you must wait to the connection be established using the appropriate events before emitting something
useEffect(() => {
socket = io(ENDPOINT, {
transports: ['websocket']
});
socket.on('connect', function(){
socket.emit('hello', "Hello from the front-end!")
});
}, [ENDPOINT]);
I am using nodeJs as backend and reactJs as my frontend the thing is I emitted a socket emit function from node
var server = require('http').createServer();
var io = require('socket.io')(server);
io.emit('quantity_check', 'KR')
now the issue is I'm unable to catch the emit
let serverUrl = 'localhost:3008'
const socket = socketIOClient(serverUrl);
socket.on("quantity_check", data => this.setState({ kiiii: data }));`
const socket = socketIOClient(serverUrl);
I'm checking this locally even i tried with my ip its not connecting I am not sure where the issue occurs
pc:nodejs and reactjs running on different ports
Can you post the code of you node server file and the react file where are you are listening to the sockets?. Anyway i hope that emit event is inside the connection
io.on('connection', function(socket) {
io.emit('quantity_check', 'KR')
}
and did you use the life cycle method componentDidMount to receive message
componentDidMount() {
socket.on("quantity_check", data => {
console.log(data);
});
}
Try something like this.
server
const server = require('http').createServer();
const io = require('socket.io')(server);
io.on('connect', (socket) => {
io.emit('quantity_check', 'KR');
});
Client(React side)
import io from 'socket.io-client';
const socket = io('http://localhost:3008');
export class App extends Component {
componentDidMount() {
socket.on('connect', () => {
console.log(socket.connected);
});
socket.on("quantity_checke", data => {
console.log(data);
});
}
render().......
}