This is my index.js on the server side
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const PORT = process.env.PORT || 5000;
const router = require('./router');
const io = require('socket.io')(server, {
cors: {
origin: '*',
}
});
io.sockets.on('connection', (socket) => {
console.log('We have a new connection');
socket.on('join', () => {
console.log(name, room);
});
socket.on('disconnect', () => {
console.log('User left!!');
});
},)
app.use(router);
server.listen(PORT, () => console.log(`Server Started at ${PORT}`));
It throws an error of this function not callable. Also,
This is my Chat.js (Chat Component) on the client-side.
import React, {useState, useEffect} from 'react';
import queryString from 'query-string';
import io from 'socket.io-client';
import './Chat.css';
let socket;
const Chat = ( { location }) => {
const [name, setName] = useState("");
const [room, setRoom] = useState("");
const ENDPOINT = 'localhost:5000';
socket = io.connect(ENDPOINT);
useEffect(() => {
const {name, room} = queryString.parse(location.search);
setName(name);
setRoom(room);
socket.emit('join', { name, room });
}, [ENDPOINT, location.search]);
return (
<h1>Chat</h1>
)
};
export default Chat;
The major problem I am facing here is that the useEffect is getting called multipile times even after I initilaized an array.
What you need to do is to define and connect to it socket-client on App.js instead of initializing it in Chat.js. In Chat.js, you just need to create its object. It should solve the issue of multiple useEffect calls.
**Edit
In App.js add these lines to intialize and connect
import io from 'socket.io-client';
let socket;
const ENDPOINT = 'localhost:5000';
socket = io.connect(ENDPOINT);
And In Chat.js use below code at its respective place to emit events
import io from 'socket.io-client';
let socket;
socket.emit('join', { name, room });
Related
I wrote a simple hook to connect react and socket.io:
import io from 'socket.io-client'
import { useEffect, useRef } from 'react'
import { v1 as uuid } from 'uuid';
import { useParams } from "react-router-dom";
const SERVER_URL = 'http://localhost:3001'
export const useSocketConnection = () => {
const { gameId } = useParams()
const userId = uuid()
const socketRef = useRef()
useEffect(() => {
console.log('connectSocket')
socketRef.current = io(SERVER_URL, {
query: { gameId }
})
socketRef.current.emit('join-room', {
userId
})
return () => {
console.log('disconnectSocket')
socketRef.current.disconnect()
}
}, [gameId])
}
the server code is pretty simple:
const express = require("express");
const http = require("http");
const app = express();
const server = http.createServer(app);
const socket = require("socket.io");
const io = socket(server);
const cors = require('cors');
app.use(cors({credentials: true, origin: 'http://localhost:3000'}));
app.get('/', (req, res) => {
res.send('This endpoint works pretty fine')
})
io.on('connection', socket => {
console.log('connected user', socket.id, new Date()) //this log works
socket.on('join-room', () => {
console.log('hope this will work') //doesn't work at all
})
});
server.listen(3001, () => console.log('server is running on port 3001'));
when component renders useEffect hook hires just one time(look screen below)
But server gets one more connection every 5 or 6 seconds I don't know why. If look to the image below each connection has new id and the period of adding new connections is 6 seconds. Also socket.on('join room') doesnt work at all :(
Please help to figure out what Im doing wrong, couldn't find nothing helpful in the internet 🥺🥺🥺.Thank you in advance <3
I'm trying to set up a simple socket.io echo server on Heroku using Express and React. The server returns the React site from the build folder, then listens for incoming messages using onAny(). Everything works fine locally, but when deployed to Heroku none of the client-emitted messages are going through after the connection has been established.
I've used Heroku's guide as well as create-react-app and this Medium article as my starting points, and did make sure to turn on http-session-affinity as the Heroku guide said to.
Currently, the React client is set up to emit a fixed message through the onclick handler of a <span>.
Here's the contents of server.js:
'use strict';
const path = require('path');
const express = require('express');
const socketIO = require('socket.io');
const PORT = process.env.PORT || 3000;
const app = express()
.use(express.static('build'))
.listen(PORT, () => console.log(`Listening on ${PORT}`));
const io = socketIO(app);
io.on('connection', (socket) => {
console.log('Client connected');
socket.on('disconnect', () => console.log('Client disconnected'));
socket.onAny((type, data) => {
console.log('Received:');
console.log(data);
socket.emit('echo', data);
});
});
And here is the client-side React hook that establishes the connection and emits the messages, where I replace [app-name] with the Heroku app name:
import { useEffect, useRef, useState } from "react";
import socketIOClient from "socket.io-client";
const NEW_CHAT_MESSAGE_EVENT = "newChatMessage";
// const SOCKET_SERVER_URL = 'localhost:3000';
const SOCKET_SERVER_URL = 'wss://[app-name].herokuapp.com/sockjs-node';
const useChat = (roomId) => {
const [messages, setMessages] = useState([]);
const socketRef = useRef();
useEffect(() => {
socketRef.current = socketIOClient(SOCKET_SERVER_URL, {
query: { roomId },
});
socketRef.current.on(NEW_CHAT_MESSAGE_EVENT, (message) => {
console.log(message);
const incomingMessage = {
...message,
ownedByCurrentUser: message.senderId === socketRef.current.id,
};
setMessages((messages) => [...messages, incomingMessage]);
});
return () => {
socketRef.current.disconnect();
};
}, [roomId]);
const sendMessage = (messageBody) => {
console.log('sendMessage()');
socketRef.current.emit(NEW_CHAT_MESSAGE_EVENT, {
body: messageBody,
senderId: socketRef.current.id,
});
};
return { messages, sendMessage };
};
I have read blogs and seen videos where this results in successful connection between the server and client, but for some reason it doesn't seem to work on my system.
This is the code on the server side:
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
const PORT = 3001;
io.on('connection', socket => {
console.log('a user connected.');
});
http.listen(PORT, () => {
console.log('listening on port ' + PORT);
});
And this is the code on the client side:
import React, { useEffect } from 'react';
import io from 'socket.io-client';
const socket = io('http://127.0.0.1:3001');
function Test() {
return (
<div>
Test
</div>
)
}
export default Test;
I have checked the versions of both socket.io and socket.io-client and they are at 3.0.4
I have tried using io.connect(url) instead of just io(url)
I have tried replacing 127.0.0.1 with localhost and even 192.168.29.101. (I'm sorry, just a beginner and not sure how these things work in depth).
Thanks for all the help!
You could try to wrap the socket in useEffect() and add transports. Something like that:
import React, { useState, useEffect } from "react";
import openSocket from "socket.io-client";
function App() {
const [response, setResponse] = useState("");
useEffect(() => {
const socket = openSocket("http://localhost:3001", {
transports: ["websocket"],
});
socket.on("message", data => {
setResponse(data);
});
}, []);
return (
<p>
{response}
</p>
);
}
export default App;
In your server you need to specify the event to emit:
const express = require("express");
const app = express();
const server = app.listen(3001, () => {
console.log("listening on port 3001");
});
const io = require("socket.io")(server);
io.on("connection", (socket) => {
console.log("Client connected");
socket.emit("message", "Hello Socket!");
});
This is my Server program
const express = require('express')
const socketio = require('socket.io')
const http = require('http')
const cors = require('cors')
const PORT = process.env.PORT || '5000'
const router = require('./router')
const app = express()
const server = http.createServer(app)
const io = socketio(server)
app.use(cors())
app.use(router)
io.on('connection', socket => {
console.log('User has connected.')
socket.on('join', ({name,room}) => {
console.log(name,room)
})
socket.on('disconnect', () => {
console.log("User has disconnected.")
})
})
server.listen(PORT, () => console.log(`Server running on port ${PORT}`))
and this is my Client side program
import React, { useState, useEffect } from "react"
import queryString from 'query-string'
import io from 'socket.io-client'
let socket
const Chat = ({ location }) => {
// eslint-disable-next-line
const [name, setName] = useState('')
// eslint-disable-next-line
const [room, setRoom] = useState('')
const ENDPOINT = 'localhost:5000'
useEffect(() => {
const { name, room } = queryString.parse(location.search);
socket = io(ENDPOINT)
setRoom(room)
setName(name)
socket.emit('join', {name, room})
}, [ENDPOINT, location.search])
return (
<div className='chat'>
<h1>Test</h1>
</div>
)
}
export default Chat
There's no error in the code, the react app seems to working fine , but I couldn't get the connection establishment .
I don't get the Connected console log or Client Connected console log and I don't know why!
I cannot figure out why my React component is not updating once the viewer count changes. When the page first renders, the amount is displayed correctly. Socket events are logged to my terminal also just fine.
There is probably an easy fix to this. What am I doing wrong?
Server
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const port = process.env.PORT || 4001;
const index = require('./index');
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socketIo(server);
io.on('connection', (socket) => {
console.log('+ client connected');
getApiAndEmit(socket);
socket.on('disconnect', () => {
console.log('- Client disconnected');
getApiAndEmit(socket);
});
});
const getApiAndEmit = (socket) => {
socket.emit('event', io.engine.clientsCount);
};
server.listen(port, () => console.log(`Listening on port ${port}`));
React
import React from 'react';
import socketIOClient from 'socket.io-client';
class App extends React.Component {
constructor() {
super();
this.state = {
response: false,
endpoint: 'http://localhost:4001',
};
}
componentDidMount() {
const { endpoint } = this.state;
const socket = socketIOClient(endpoint);
socket.on('event', (data) => this.setState({ response: data }));
}
render() {
const { response } = this.state;
return (
<p>{response ? <p>Active Users {response}</p> : <p>Loading...</p>}</p>
);
}
}
export default App;
I think the problem is that you're using the wrong type of emit. Take a look at this cheat sheet: https://socket.io/docs/emit-cheatsheet/
If you use socket.emit(), socketio only sends the event to the single, connected client, if you use socket.broadcast.emit(), it emits the event to every client except the sender, and if you use io.emit(), it emits the event to every client.
So I think your code should look something like:
io.on('connection', (socket) => {
io.emit('event', io.engine.clientsCount);
socket.on('disconnect', () => {
socket.broadcast.emit('event', io.engine.clientsCount);
});
});
Try this:
componentDidMount() {
const { endpoint } = this.state;
const socket = socketIOClient(endpoint);
let self = this;
socket.on('event', (data) => self.setState({ response: data }));
}