I'm implementing a chat feature with Socket.io in a React Native Expo app. The socket connects when opening the chat screen and sends a message to the client. It also receives a message from the client without issue. It isn't until I try to emit a message from the client to server, to then be received and sent back that I have the issue. I am using a text input and useState. The sendMessage function works as expected if I replace the useState data with a static string, but not with the updated state unless I save the client page and then hit send. Below is my code:
Client
// TestScreen.js (Client)
import { io } from 'socket.io-client';
import { NGROK_URL } from '../api/ngrok';
const TestScreen = () => {
const [currentMessage, setCurrentMessage] = useState('');
const [arrivalMessage, setArrivalMessage] = useState('');
const socket = io(NGROK_URL, { autoConnect: false });
const sendMessage = () => {
setArrivalMessage(currentMessage);
socket.emit('send_msg', {
to: 'Server',
from: 'Client',
message: currentMessage,
});
};
useEffect(() => {
socket.connect();
socket.on('welcome', (arg) => console.log(arg));
socket.emit('client', 'Hello from the client!');
socket.on('receive_msg', ({ message }) => {
console.log(`From receive msg: ${message}`);
});
return () => socket.disconnect();
}, []);
Server
// index.js (Server)
const PORT = process.env.PORT || 5000;
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST'],
},
});
const onSendMessage = (data) => {
console.log(data);
io.emit('receive_msg', data);
};
const onConnection = (socket) => {
console.log(`User Connected: ${socket.id}`);
// Send a message to the client
socket.emit('welcome', 'Hello from the server!');
// Receive message from the client
socket.on('client', (arg) => console.log(arg));
socket.on('send_msg', onSendMessage);
socket.on('disconnect', (reason) =>
console.log(`User disconnected due to ${reason}.`)
);
};
io.on('connection', onConnection);
httpServer.listen(
PORT,
console.log(
`Server is running in ${process.env.NODE_ENV} on port ${PORT}`.yellow.bold
)
);
Related
My frontend service is running on netlify.
And backend is on heroku.
I am trying to make chatApp.
After I entered chatRoom press sending button below error message pop up on console log.
"Failed to execute 'send' on 'WebSocket': Still in CONNECTING state."
I guess
problem is below code.
client
created() {
this.channel = this.$route.query.channel || '';
this.$store.state.user.stateWebSocket = new WebSocket('ws://peaceful-ridge-59102.herokuapp.com:9999/ws');
// this.websocket = new SockJS('http://localhost:8080/ws/realtime');
this.websocket=this.$store.state.user.stateWebSocket;
this.websocket.onmessage = ({ data }) => {
const vo = JSON.parse(data);
if (vo.channel === this.channel) {
this.appendNewMessage(this.tempName, vo.message, vo.time);
}
};
this.websocket.onopen = (event) => {
console.log('open event..', event);
};
this.websocket.onerror = (event) => {
console.log('error', event);
};
this.websocket.onclose = (event) => {
console.log('close', event);
};
}
This is sever.js
const cors = require('cors');
const express = require('express');
const app = express();
const WebSocket = require('ws');
const PORT = 9999;
app.use(
cors({
origin: true,
credentials: true,
})
);
const server = app.listen(PORT, () => {
console.log(PORT, 'waiting unitil connects');
});
app.get('/', (req, res) => {
res.send('Hello World!');
});
const wss = new WebSocket.Server({ server, path: '/ws' });
wss.on('connection', (ws, req) => {
// connection
console.log('새로운 클라이언트 접속');
ws.on('message', (message) => {
// receiving message
const json = JSON.parse(message.toString());
json.time = Date.now()
message = JSON.stringify(json)
console.log(message.toString());
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message.toString());
}
});
// Runs when client disconnects
wss.on('disconnect', () => {
});
});
ws.on('error', (err) => {
// error
console.error(err);
});
ws.on('close', () => {
// close
console.log('Client close');
clearInterval(ws.interval);
});
});
some people say I am sending your message before the WebSocket connection is established.
I am newbie on JS plz help me~!
I want to build a ReactJS/NodeJs app with Socket IO.
I am able to establish a socket connection between the client and the server, but whenever I press the button to emit a message, nothing happens on the server side, meaning the console.log('new message:', msg)is not triggered.
Client code:
import React from 'react';
import io from 'socket.io-client';
const socket = io.connect('http://localhost:4000');
function App() {
socket.on('message', msg => {
console.log('new message:', msg);
});
const handleMessageSend = () => {
socket.emit('message', 'test');
}
return (
<button onClick={handleMessageSend}>Send</button>
);
}
export default App;
Server:
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
io.on('connection', socket => {
socket.on('message', msg => {
console.log('new message:', msg);
socket.emit('message', msg)
})
})
http.listen(4000, () => {
console.log('Listening on port 4000');
})
Any ideas ? Thanks a lot in advance
I have moved socket code inside handleMessageSend.
And you can add preventDefault to prevent your page refreshing (I am not sure if you need this because you are not using a form and submit button, but you can use it for now.)
Can you please try this and let me know if it works?
React component:
import io from 'socket.io-client';
function App() {
let serverUrl = 'localhost:4000'
let socket = io(serverUrl);
const handleMessageSend = (e) => {
e.preventDefault();
socket.emit("message", "test message")
socket.on("message", function(msg){
console.log("socket working on the frontend: ", msg);
});
}
return (
<button onClick={handleMessageSend}>Send</button>
);
}
export default App;
And here server file :
const express = require ("express");
const socket = require ("socket.io");
const app = express();
const server = app.listen(4000, () => {
console.log('Listening on port 4000');
})
const io = socket(server);
io.on('connection', socket => {
socket.on('message', msg => {
console.log('socket working at the backend', msg);
io.sockets.emit('message', msg)
})
})
I'm building a messaging feature with socket.io and a React frontend. With a socket.io only server it is working as expected, with the following code:
Socket.io server only
const io = require("socket.io")(5000, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
},
});
io.on("connection", (socket) => {
const id = socket.handshake.query.id;
socket.join(id);
socket.on("send-message", ({ recipients, text }) => {
recipients.forEach((recipient) => {
const newRecipients = recipients.filter((r) => r !== recipient);
newRecipients.push(id);
socket.broadcast.to(recipient).emit("receive-message", {
recipients: newRecipients,
sender: id,
text,
});
});
});
});
I am trying to integrate with express. The server is starting with the code below but messaging is no longer working:
Express server
const express = require("express");
const socketIo = require("socket.io");
const cors = require("cors");
const PORT = process.env.PORT || 5000;
const app = express();
const http = app.listen(PORT, () =>
console.log(`🚀 Server ready at http://localhost:${PORT}`)
);
const io = socketIo(http, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST", "send-message", "receive-message"],
},
});
io.once("connection", (socket) => {
const id = socket.handshake.query.id;
socket.join(id);
socket.on("connect_error", (err) => {
console.log(`connect_error due to ${err.message}`);
});
socket.on("send-message", ({ recipients, text }) => {
recipients.forEach((recipient) => {
const newRecipients = recipients.filter((r) => r !== recipient);
newRecipients.push(id);
socket.broadcast.to(recipient).emit("receive-message", {
recipients: newRecipients,
sender: id,
text,
});
});
});
});
Running it locally for both instances in Chrome with a window and another incognito window open on localhost:3000
As described here on('connection') event on client side not work. Change it to on('connect');
// server-side
io.on("connection", (socket) => {
console.log(socket.id); // x8WIv7-mJelg7on_ALbx
});
// client-side
socket.on("connect", () => {
console.log(socket.id); // x8WIv7-mJelg7on_ALbx
});
I try to connect to a socket.io-client using the following code:
client:
import queryString from 'query-string';
import React, { useEffect, useState } from 'react';
import io from 'socket.io-client';
let socket;
const Chat = ({location}) => {
const [name, setName] = useState("");
const [room, setRoom] = useState("");
const EP = 'http://localhost:5000/';
useEffect(() =>{
const {name , room} = queryString.parse(location.search);
socket = io(EP);
setName(name);
setRoom(room);
console.log(socket);
},[EP, location.search])
return(
<h1>helloooooooooooooo {name} welcome to {room}</h1>
)
}
export default Chat;
server:
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const router = require('./router/router');
const PORT = process.env.PORT ||5050;
const app = express();
const server = http.createServer(app);
const io = socketio(server);
//socket.io
io.on('connection', socket => {
console.log("we have a new user!!!!!!!!!");
socket.on('disconnect', () =>{
console.log('User had left!');
})
})
// io.on('connection', socket => {
// console.log("we have a new user!!!!!!!!");
// socket.on("disconnect", () => console.log("user is left"))
// });
app.use(router);
server.listen(PORT, () => console.log(`Server has started on ${PORT}`));
i dont get connet or disconnect console log from this server socket.
i follow same process as socke.io doc.
console message from browser, its showing disconnected true and connected false and no id
Since Socket.IO v3, you need to explicitly enable Cross-Origin Resource Sharing (CORS).
https://socket.io/docs/v3/handling-cors/
// server-side
const io = require("socket.io")(httpServer, {
cors: {
origin: "https://example.com",
methods: ["GET", "POST"],
allowedHeaders: ["my-custom-header"],
credentials: true
}
});
// client-side
const io = require("socket.io-client");
const socket = io("https://api.example.com", {
withCredentials: true,
extraHeaders: {
"my-custom-header": "abcd"
}
});
in client, inside useEffect instead of
socket = io(EP);
to this
socket = io.connect(EP , {
"force new connection" : true,
"reconnectionAttempts": "Infinity",
"timeout" : 10000,
"transports" : ["websocket"],
withCredentials:true,
extraHeaders:{
"my-custom-header": "abcd"
}
});
i got this solution from this question
In the browser, the WebSocket object does not support additional headers. In case you want to add some headers as part of some authentication mechanism, you can use the transportOptions attribute. Please note that in this case the headers won't be sent in the WebSocket upgrade request.
// WILL NOT WORK in the browser
const socket = new Socket('http://localhost', {
extraHeaders: {
'X-Custom-Header-For-My-Project': 'will not be sent'
}
});
// WILL NOT WORK
const socket = new Socket('http://localhost', {
transports: ['websocket'], // polling is disabled
transportOptions: {
polling: {
extraHeaders: {
'X-Custom-Header-For-My-Project': 'will not be sent'
}
}
}
});
// WILL WORK
const socket = new Socket('http://localhost', {
transports: ['polling', 'websocket'],
transportOptions: {
polling: {
extraHeaders: {
'X-Custom-Header-For-My-Project': 'will be used'
}
}
}
});
Credit: Engine.IO client
I am going to make a private chat app like WhatsApp.
I connect to the server successfully
but the socket after several seconds gets disconnect from the server.
while on the client it doesn't disconnect.
Server code:
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
const onlineusers = {};
const socketid = {};
io.on('connection', cs => {
cs.on('online', username => {
if(username){
onlineusers[username] = cs.id;
socketid[cs.id] = username;
}
console.log("\nonline: ", onlineusers);
});
cs.on('disconnect', () => {
delete onlineusers[socketid[cs.id]];
console.log("\noffline: ", onlineusers);
});
});
const chat = io.of("/chat");
chat.on('connection', cs => {
cs.on('startchat', username => {
if (username){
chat.to('/chat#'+onlineusers[username]).emit('hey', 'I love programming');
}
});
});
server.listen(port, err => {
if(err){
console.error("Some Error: "+err);
}else{
console.log(`Server is running on port: ${port}`);
}
});
MY CLIENT code is by react-native and socket.io-client:
On line users file:
import io from 'socket.io-client';
const SocketEndpoint = 'http://192.168.43.172:3000';
this.socket = io(SocketEndpoint, {
transports: ['websocket']
});
this.socket.on('connect', () => {
if (this.state.username) {
this.socket.emit("online", this.state.username);
}
});
this.socket.on('connect_error', (err) => {
Alert.alert(err);
});
this.socket.on('disconnect', () => {
Alert.alert('disconnected');
});
Chat page file:
import io from 'socket.io-client';
const SocketEndpoint = 'http://192.168.43.172:3000/chat';
this.socket = io(SocketEndpoint, {
transports: ['websocket']
});
this.socket.on('connect', () => {
if (theirusername) {
this.socket.emit('startchat', theirusername);
}
this.socket.on('hey', data => {
alert(data);
});
this.socket.on('janajan', data => {
alert(data);
});
});
I want to keep to client socket on the server until the client themselves gets the disconnect.
because here when I want to say hey it gets a disconnect and my message could pass to the client.
thank you before