I am facing a problem where the react is rendering 2 times but I do not see any problem in the code or it is come from the socket? I noticed this problem when consoling and when displaying data, the data duplicate. Below I put my client react code with the server socket code.
React client
import "./App.css";
import io from "socket.io-client";
import { useEffect, useState } from "react";
const socket = io.connect("http://localhost:3001");
function App() {
const [text, setText] = useState("");
const [room, setRoom] = useState("");
const [data, setData] = useState([]);
const [action, setAction] = useState(true);
console.log("data", data);
console.log(text);
console.log(room);
const sendMessage = () => {
socket.emit("send_message", { text, room });
};
const joinRoom = () => {
if (room !== "") {
socket.emit("join_room", room);
}
};
useEffect(() => {
socket.on("receive_message", (msg) => {
setData((prev) => [
...prev,
{
message: msg,
},
]);
});
}, [action]);
return (
<div className="App">
{data.map((da) => (
<p>{da.message}</p>
))}
<input
type="text"
placeholder="room no"
onChange={(e) => {
setRoom(e.target.value);
}}
></input>
<button onClick={joinRoom}>Join</button>
<br />
<input
type="text"
placeholder="message .."
onChange={(e) => {
setText(e.target.value);
}}
></input>
<button onClick={sendMessage}>Send Message</button>
</div>
);
}
export default App;
Socket server
const express = require("express");
const app = express();
const http = require("http");
const { Server } = require("socket.io");
const cors = require("cors");
app.use(cors());
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
},
});
io.on("connection", (socket) => {
// console.log(`User Connected ${socket.id}`);
socket.on("join_room", (data) =>{
socket.join(data);
})
socket.on("send_message", (data) => {
socket.to(data.room).emit("receive_message", data.text);
})
});
server.listen(3001, () => {
console.log("SERVER OK");
});
Related
Attempting to create a simple React chat app, but I'm running into an issue where duplicate messages appear. I run the server with node server.js, in a separate terminal run the client with npm start, then open two windows at localhost:3000. I can send a message, but any message I send is received x2. For example (after submitting the form with "i only sent this once" on one window, this is what appears in the second window).:
I did console.log on the server-side, and only one message is being received from the server.
Here is my server.js file:
const express = require("express");
const socketio = require("socket.io");
const http = require("http");
const cors = require("cors");
const PORT = process.env.PORT || 5001;
const app = express();
const server = http.createServer(app);
const io = socketio(server);
app.use(cors());
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
io.on("connection", (socket) => {
socket.on("connection", () => {});
socket.on("send-message", (message) => {
console.log(message);
socket.broadcast.emit("message", message);
});
});
Here's my socket.js file:
import io from "socket.io-client";
const SERVER = "http://127.0.0.1:5001";
const connectionOptions = {
forceNew: true,
reconnectionAttempts: "Infinity",
timeout: 10000,
transports: ["websocket"],
};
let socket = io.connect(SERVER, connectionOptions);
export default socket;
Here's my App.js file:
import { useState, useEffect } from "react";
import "./App.css";
import socket from "./socket";
const ChatWindow = () => {
const [message, setMessage] = useState("");
const [messages, setMessages] = useState([]);
const handleMessageChange = (event) => {
setMessage(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
socket.emit("send-message", { message: message });
};
useEffect(() => {
socket.on("connection", null);
socket.on("message", (payload) => {
setMessages((prev) => {
return [...prev, payload.message];
});
});
}, []);
return (
<div>
{messages.map((message) => {
return <h3>message: {message}</h3>;
})}
<form onSubmit={handleSubmit}>
<input value={message} onChange={handleMessageChange}></input>
<button type="submit">Send Message</button>
</form>
<h1>Chat Window</h1>
</div>
);
};
function App() {
return (
<div className="App">
<ChatWindow />
</div>
);
}
export default App;
As punjira answered in a comment, removing the event listener for the useEffect worked.
Specifically, before:
useEffect(() => {
socket.on("connection", null);
socket.on("message", (payload) => {
setMessages((prev) => {
return [...prev, payload.message];
});
});
}, []);
After:
useEffect(() => {
socket.on("connection", null);
socket.on("msg", (payload) => {
setMessages((prev) => {
return [...prev, payload.msg];
});
});
return function cleanup() {
socket.removeListener("msg");
};
}, []);
If you are using UseEffects Hooks you need to clean up
Before :
useEffect(() => {
socket.on("connection", null);
socket.on("message", (payload) => {
setMessages((prev) => {
return [...prev, payload.message];
});
});
}, []);
You can add this line to clean up :
useEffect(() => {
socket.on("connection", null);
socket.on("message", (payload) => {
setMessages((prev) => {
return [...prev, payload.message];
});
});
return () => socket.off("message"); // add this line to your code
}, []);
emitting messages to server working fine but when i try to get message from server its not working.
tried different useEffect dependencies (incomingMessage etc.), after some search all sources using socket as dependency.
in server side messages is appear tring to send message to client
client
import io from "socket.io-client";
import { useEffect, useState } from "react";
const socket = io("http://localhost:3001");
function App() {
const [loading, setLoading] = useState(true);
const [message, setMessage] = useState("");
const [incomingMessage, setIncomingMessage] = useState([]);
useEffect(() => {
socket.on("connect", () => {
setLoading(false);
});
},[]);
const sendMessage = (e) => {
e.preventDefault();
socket.emit("message", message);
setMessage("");
};
useEffect(() => {
socket.on("new-message", (data) => {
console.log("new message", data);
setIncomingMessage(data);
});
console.log("incoming message", incomingMessage);
}, [socket]);
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<h1>{socket.id}</h1>
<input value={message} onChange={(e) => setMessage(e.target.value)} />
<button onClick={sendMessage}>Send</button>
<p>{incomingMessage}</p>
</div>
);
}
export default App;
server
import express from "express";
import { createServer } from "http";
import { Server } from "socket.io";
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
},
});
io.on("connection", (socket) => {
socket.on("message", (data) => {
console.log(data);
socket.emit("new-message", data);
});
});
httpServer.listen(3001);
MongoDB connection is being refused at port connection 3001, it was working before but suddenly it stopped working. My database is on MongoDB atlas. I am connected through mongoDB compass and I have the connection link in my code. I followed a mern tutorial exactly but am still facing this issue: https://www.youtube.com/watch?v=I7EDAR2GRVo. Does anyone have any idea why this would happen?
import "./App.css";
import { useState, useEffect } from "react";
import Axios from "axios";
function App() {
const [listOfUsers, setListOfUsers] = useState([]);
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const [username, setUsername] = useState("");
useEffect(() => {
Axios.get("http://localhost:3001/getUsers").then((response) => {
setListOfUsers(response.data);
});
}, []);
const createUser = () => {
Axios.post("http://localhost:3001/createUser", {
name,
age,
username,
}).then((response) => {
setListOfUsers([
...listOfUsers,
{
name,
age,
username,
},
]);
});
};
return (
<div className="App">
<div className="usersDisplay">
{listOfUsers.map((user) => {
return (
<div>
<h1>Name: {user.name}</h1>
<h1>Age: {user.age}</h1>
<h1>Username: {user.username}</h1>
</div>
);
})}
</div>
<div>
<input
type="text"
placeholder="Name..."
onChange={(event) => {
setName(event.target.value);
}}
/>
<input
type="number"
placeholder="Age..."
onChange={(event) => {
setAge(event.target.value);
}}
/>
<input
type="text"
placeholder="Username..."
onChange={(event) => {
setUsername(event.target.value);
}}
/>
<button onClick={createUser}> Create User </button>
</div>
</div>
);
}
export default App;
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const UserModel = require("./models/Users");
const cors = require("cors");
app.use(express.json());
app.use(cors());
mongoose.connect("mongodb+srv://username:password#cluster0.md4aag2.mongodb.net/merntutorial?retryWrites=true&w=majority");
app.get("/getUsers", (req, res) => {
UserModel.find({}, (err, result) => {
if (err) {
res.json(err);
} else {
res.json(result);
}
})
});
app.post("/createUser", async (req, res) => {
const user = req.body;
const newUser = new UserModel(user);
await newUser.save();
res.json(user);
});
app.listen(3001, () => {
console.log("SERVER RUNS PERFECTLY!");
});
Search services.msc in your device and click start to run the MongoDB server.
After start or restart running MongoDB server, you will be able to run your program
I am new and I am following a tutorial of socket.io for real-time chatting. Users join the room and then a text box will appear. When Users type the message and send it, the messages object must store the message.
message is sending from the server but on the client side messages are not updating with the new message. Is useEffect not working? Or how can I get the array updated?
Chat.js
import queryString from 'query-string';
import io from 'socket.io-client';
let socket;
const Chat = ({ location }) => {
const [name, setName] = useState('');
const [room, setRoom] = useState('');
const [message, setMessage] = useState('');
const [messages, setMessages] = useState([]);
const ENDPOINT = 'localhost:5000';
useEffect(() => {
const { name, room } = queryString.parse(location.search);
socket = io(ENDPOINT);
setName(name);
setRoom(room);
socket.emit('join', { name, room }, () => {
});
return () => {
socket.disconnect();
}
},[ENDPOINT, location.search]);
useEffect(() => {
socket.on('message', (message) => {
setMessages([...messages, message]);
});
}, [messages]);
const sendMessage = (event) => {
event.preventDefault();
if (message) {
socket.emit('sendMessage', message, () => setMessage(''));
}
console.log(message, messages);
}
return (
<div className="outerContainer">
<div className="container">
<input
value={message}
onChange={event => setMessage(event.target.value)}
onKeyPress={event => event.key === 'Enter' ? sendMessage(event) : null}
/>
</div>
</div>
);
};
export default Chat;
index.js
const socketio = require('socket.io');
const http = require('http');
const { addUser, removeUser, getUser, getUsersInRoom } = require('./users');
const PORT = process.env.PORT || 5000;
const router = require('./router');
const app = express();
const server = http.createServer(app);
const io = socketio(server, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"]
},
});
io.on('connection', (socket) => {
socket.on('join', ({ name, room }, callback) => {
const { error, user} = addUser({ id: socket.id, name, room});
if (error) {
return callback(error);
}
socket.emit('message', { user: 'admin', text: `${user.name}, welcome to the room ${user.room}`});
socket.broadcast.to(user.room).emit('message', { user: 'admin', text: `${user.name}, has joined`});
socket.join( user, room);
callback();
});
socket.on('sendMessage', (message, callback) => {
const user = getUser(socket.id);
io.to(user.room).emit('message', { user: user.name, text: message});
callback();
});
socket.on('disconnect', () => {
console.log('User had left!!!');
});
});
app.use(router);
server.listen(PORT, () => console.log(`Server has started ${PORT}`));```
The problem is that you are updating the messages state in useEffect() which has messages as one of the dependencies. U can fix this problem by passing a callback to setMessages() like this:
setMessages(prevMessages => [...prevMessages, message])
and remove the messages dependency from the dependency array.
i want to make a chat app with react and socket.io
i downloaded code from https://github.com/adrianhajdin/project_chat_application.
I want to add upload file function using socketio_file_upload
but when i upload the img. there is nothing happen..
this is my code
index.js (server)
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const siofu = require("socketio-file-upload");
const { addUser, removeUser, getUser, getUsersInRoom } = require('./users');
const PORT = process.env.PORT || 5000
const router = require('./router')
const app = express()
console.log(app,'------------------app----------')
const server = http.createServer(app)
const io = socketio(server)
io.on('connection', (socket)=>{
const uploader = new siofu();
uploader.dir = "/uploads";
uploader.listen(socket);
uploader.on("saved", function(event){
});
uploader.on("error", function(event){
});
socket.on('join', ({name, room}, callback)=>{
const { user, error } = addUser({ id:socket.id, name, room })
if(error) {
return callback(error)
}
//admin system정보 여기서
socket.emit('message', { user:'admin', text:`${user.name}, welcome to the room ${user.room}` })
//braodcast는 room에 있는 모든 사람에게 msg를 보낸다.
socket.broadcast.to(user.room).emit('message', { user: 'admin', text: `${user.name} has joined!` });
socket.join(user.room)
io.to(user.room).emit('roomData', {room: user.room, users: getUsersInRoom(user.room)})
callback()
})
socket.on('sendMessage', (message, callback) => {
const user = getUser(socket.id);
io.to(user.room).emit('message', { user: user.name, text: message });
io.to(user.room).emit('roomData', { room: user.room, users: getUsersInRoom(user.room)});
callback();
});
socket.on('disconnect', () => {
const user = removeUser(socket.id)
io.to(user.room).emit('message', { user:'admin', text: `${user.name} has left`})
})
})
app.use(siofu.router)
server.listen(PORT, ()=> console.log('---SERVER START---'))
Chat.jsx
import React, { useState, useEffect, useRef } from 'react';
import queryString from 'query-string'
import io from 'socket.io-client'
import './chat.css'
import InfoBar from '../InfoBar/InfoBar'
import Messages from '../Messages/Messages'
import Input from '../Input/Input'
let socket ='default'
const Chat = ({location}) => {
const [name, setName] = useState('');
const [room, setRoom] = useState('');
const [message, setMessage] = useState('')
const [messages, setMessages] = useState([])
const END_POINT = 'localhost:5000'
//componentdidmount와 같다
useEffect(()=>{
const {name, room} = queryString.parse(location.search)
socket = io(END_POINT)
setName(name)
setRoom(room)
//server에 join을 통해서 데이터를 보냄
socket.emit('join', {name, room}, (res)=>{
})
//useEffect()애서 return 은 unmount와 같다. 즉 user leave일 때 사용!
return () =>{
socket.emit('disconnect')
socket.off()
}
},[END_POINT, location.search])
useEffect(() => {
socket.on('message', (message) =>{
setMessages([...messages, message])
})
// uploader.listenOnInput(document.getElementById("siofu_input"));
}, [messages])
const sendMessage = (event) => {
event.preventDefault();
if(message) {
socket.emit('sendMessage', message, () => setMessage(''));
}
}
return (
<div className="outerContainer">
<div className="container">
<InfoBar room={room} />
<Messages messages={messages} name={name} />
<Input socket={socket} message={message} setMessage={setMessage} sendMessage={sendMessage} />
</div>
</div>
);
};
export default Chat;
Input.jsx
import React, { Component } from 'react';
import SocketIOFileUpload from '../../../../server/node_modules/socketio-file-upload'
import './input.css';
class Input extends Component {
uploadFile = (e) => {
const {socket} = this.props
console.log("uploading");
// const files = e.target.files;
const siofu = new SocketIOFileUpload(socket);
siofu.listenOnInput(document.getElementById("siofu_input"));
};
render() {
const { setMessage, sendMessage, message, socket } = this.props
return (
<form className="form">
<input
className="input"
type="text"
placeholder="Type a message..."
value={message}
onChange={({ target: { value } }) => setMessage(value)}
onKeyPress={event => event.key === 'Enter' ? sendMessage(event) : null}
/>
<input type="file" id="siofu_input" onChange={this.uploadFile.bind(this)}/>
<button className="sendButton" onClick={e => sendMessage(e)}>Send</button>
</form>
);
}
}
export default Input;
users.js
const users = [];
const addUser = ({ id, name, room }) => {
name = name.trim().toLowerCase();
room = room.trim().toLowerCase();
const existingUser = users.find((user) => user.room === room && user.name === name);
if(!name || !room) return { error: 'Username and room are required.' };
if(existingUser) return { error: 'Username is taken.' };
const user = { id, name, room };
users.push(user);
return { user };
}
const removeUser = (id) => {
const index = users.findIndex((user) => user.id === id);
if(index !== -1) return users.splice(index, 1)[0];
}
const getUser = (id) => users.find((user) => user.id === id);
const getUsersInRoom = (room) => users.filter((user) => user.room === room);
module.exports = { addUser, removeUser, getUser, getUsersInRoom };
How can i upload img file to chat app....
At first, you must create "uploads" folder to upload files.
When I run the app on local, I created folder on to D drive and changed uploader.dir from '/uploads' to "uploads";
At second, when you select DOM, you used document.elementById, this is wrong, must use ref={(el)=>this.variable=el} and change to siofu.listenOnInput(this.variable);
At third, you did define upload logic in onChange event listener, have to define in componentDidMount().