import ...
let socket;
const Game = () => {
const ...
const [userCount, setUserCount] = useState(0);
const scrollToBottom = () => {
endToMessages.current?.scrollIntoView({ behavior: "smooth" });
};
const { _id, username } = JSON.parse(localStorage.getItem("user")).user;
useEffect(() => {
socket = io(process.env.REACT_APP_BASE_URL);
socket.emit("game_lobby", { id: _id, username, room: gameInfo.name });
return () => socket.disconnect();
}, [_id, username, gameInfo.name]);
useEffect(() => {
socket.on("message", ({ user, text }) => {
setMessages((prev) => [...prev, { user, text }]);
scrollToBottom();
});
socket.on("user_count",({count}) => {
setUserCount(count);
})
}, []);
console.log("Current user count",userCount);
const sendMessage = () => {
...
};
return (
<div className="game section">
...
</div>
);
};
export default Game;
Server side:
import { Server } from "socket.io";
const socketApi = (server) => {
const io = new Server(server, {
cors: {
origin: ["https://mook-f2b4e.web.app", "http://localhost:3000"],
methods: ["GET", "POST"],
},
});
io.on("connection", (socket) => {
socket.on("disconnect", () => {
console.log(`user ${socket.id} had left`);
});
socket.on("game_lobby", async ({ id, username, room }) => {
console.log("We have a new connetion.");
socket.join(room);
const roomClients = await (await io.in(room).fetchSockets()).length;
console.log(roomClients);
io.to(room).emit("user_count", { count: roomClients });
socket.on("disconnect", () => {
io.to(room).emit("user_count", { count: roomClients });
});
socket.emit("message", {
user: "Admin",
text: `${username} welcome to ${room} room`,
});
});
socket.on("send_message", ({ name, message, room }) => {
io.to(room).emit("message", { user: name, text: message });
});
});
return io;
};
export default socketApi;
Hi all.When I try to get user count when component mount but I can't.First time when component did mount I get 0 value. If someone else joins the room then I can get its current value. If I could explain properly I mean let's say there are 3 people in the room and I joined that room later. Now there are 4 people in the room but I got 0 value from console.log("Current user count", userCount) if the 5th person joins the room then I can get the current value from the server.
I believe you would need the server to have a variable to keep track of active users. So connection increment a variable for onlineUsers, then on disconnect subtract one from the onlineUsers
See reference here => https://stackoverflow.com/a/10276446/3124019
Related
I'm trying to send real time message with socket.io.
But the problem is that The reciever won't receive the message until i refresh the browser.
i'm getting all the data on the console but not in recievers end
I want to make it a real time message
Below are my codes
Messenger FrontEnd
// Context State
const { friends, setFriends, message, setMessage, authInfo } = useAuth();
const [currentFriend, setCurrentFriend] = useState("");
const [activeUser, setActiveUser] = useState([]);
const [newMessage, setNewMessage] = useState("");
const [socketMessage, setSocketMessage] = useState("");
const { updateNotification } = useNotification();
useEffect(() => {
socket.current = io("ws://localhost:9000");
socket.current.on("getMessage", (data) => {
setSocketMessage(data);
});
}, []);
useEffect(() => {
if (socketMessage && currentFriend) {
if (
socketMessage.senderId === currentFriend._id &&
socketMessage.receiverId === authInfo.profile.id
) {
console.log([...message, socketMessage]); // I'm confused on what to do here
}
}
setSocketMessage("");
}, [socketMessage]);
Socket.io Backend
let users = [];
const addUser = (userId, socketId, userInfo) => {
const checkUser = users.some((u) => u.userId === userId);
if (!checkUser) {
users.push({ userId, socketId, userInfo });
}
};
const userRemove = (socketId) => {
users = users.filter((u) => u.socketId !== socketId);
};
const findFriend = (id) => {
return users.find((u) => u.userId === id);
};
io.on("connection", (socket) => {
console.log("Socket Is Connecting...");
socket.on("addUser", (userId, userInfo) => {
addUser(userId, socket.id, userInfo);
io.emit("getUser", users);
});
socket.on("sendMessage", (data) => {
const user = findFriend(data.receiverId);
if (user !== undefined) {
socket.to(user.socketId).emit("getMessage", {
senderId: data.senderId,
senderName: data.senderName,
receiverId: data.receiverId,
createAt: data.time,
message: {
text: data.message.text,
image: data.message.image,
},
});
}
});
const socketUsers = [];
io.on("connection", (socket) => {
socket.on("user", (userdata) => {
const aUser = { socket: socket, user: userdata };
socketUsers.push(aUser);
});
socket.on("disconnect", () => {
delete socketUsers[socket.id];
console.log(socketUsers);
});
});
The socket and user field is also assigned to the aUser then it's pushed into the socketUsers array. This happens after the user logs in because we need their userdata.
When the user disconnects, the console logs the array for me but the user is still there (both socket and userdata fields).
What am I doing wrong?
You are indexing the array wrong, pushing new sockets onto it won't make those sockets' ids be indexes of the array, from what i can tell you probably should use an object instead.
const socketUsers = {};
io.on("connection", (socket) => {
socket.on("user", (userdata) => {
const aUser = { socket: socket, user: userdata };
socketUsers[socket.id] = aUser;
});
socket.on("disconnect", () => {
delete socketUsers[socket.id];
console.log(socketUsers);
});
});
If you are so insistent on using an array, you would have to manually search it for index of the element you're looking for
const socketUsers = [];
io.on("connection", (socket) => {
socket.on("user", (userdata) => {
const aUser = { socket: socket, user: userdata };
socketUsers.push(aUser);
});
socket.on("disconnect", () => {
socketUsers.splice(socketUsers.findIndex(elem => elem.socket.id === socket.id), 1);
console.log(socketUsers);
});
});
I've emitted two events on user joined & left (user_joined and user_left). It's working on the server-side but not working on the client-side.
Server-side code: (it's working, showing console.log on every connection)
io.on('connection', function (socket) {
const id = socket.id;
/**
* User Join Function
*/
socket.on('join', function ({ name, room }) {
const { user } = addUser({id, name, room}); // add user to users array
socket.join(user.room);
socket.emit('user_joined', users); // emit event with modified users array
console.log(id, 'joined')
})
/**
* User Disconnect function
*/
socket.on('disconnect', () => {
removeUser(id); // remove user form users array
socket.emit('user_left', users); // emit event with modified users array
console.log(id, 'left')
})
})
Client-side code: (Not firing on user_joined or user_left)
const [players, setPlayers] = useState([]);
const ENDPOINT = 'localhost:5000';
socket = io(ENDPOINT);
useEffect(() => {
const name = faker.name.firstName() + ' ' + faker.name.lastName();
socket.emit('join', {name, room: 'global'}); // it's working fine
return () => {
socket.emit('disconnect');
socket.off();
}
}, [])
useEffect(() => {
socket.on('user_joined', (users) => {
setPlayers(users);
}); // >>> Not Working <<<
socket.on('user_left', (users) => {
setPlayers(users);
}); // >>> Not Working <<<
console.log(socket) // it's working fine
}, [players]);
The socket instance needs to be created only once. In your case, it is getting created on every re-render. Also you do not need 2 useEffects.
Put the creation of socket instance and merge your 2 useEffects into 1 and provide an empty array as dependency. With this, your useEffect is executed only once and not on every re-render.
Try this
const [players, setPlayers] = useState([]);
useEffect(() => {
const ENDPOINT = 'localhost:5000';
socket = io(ENDPOINT);
const name = faker.name.firstName() + ' ' + faker.name.lastName();
socket.emit('join', {name, room: 'global'});
socket.on('user_joined', (users) => {
setPlayers(users);
});
socket.on('user_left', (users) => {
setPlayers(users);
});
console.log(socket);
return () => {
socket.emit('disconnect');
socket.off();
}
}, []);
...
If you want to use the socket instance in other places of your component then make use of useRef. With useRef, you always get the same instance unless you mutate it.
create socket with refs
...
const [players, setPlayers] = useState([]);
const ENDPOINT = 'localhost:5000';
const socketInstance = useRef(io(ENDPOINT));// in react, with useRef, you always get the same instance unless you mutate it.
useEffect(() => {
// socketInstance.current = io(ENDPOINT);
const name = faker.name.firstName() + ' ' + faker.name.lastName();
socketInstance.current.emit('join', {name, room: 'global'});
socketInstance.current.on('user_joined', (users) => {
setPlayers(users);
});
socketInstance.current.on('user_left', (users) => {
setPlayers(users);
});
console.log(socketInstance.current);
return () => {
socketInstance.current.emit('disconnect');
socketInstance.current.off();
}
}, []);
...
I am unable to send message using socketio, Here's an function i am using but not able to send messages.
Following is the flow I am using, event wise
workspace_room_join
get_user_room
room_join
message
Now I am unable to send a message, What is the correct way to send the message?
Below code function is for sending message
sendUsingSocket = (messages) => {
const workspace_id = localStorage.getItem('workspace_id');
const payload = {
room_id:this.props.socket_details.room_id,
isChannel:false,
workspace_id:workspace_id,
chat: messages,
sender_id: this.state.sender_to_receiver_details.sender_id,
receiver_id: this.state.sender_to_receiver_details.receiver_id,
}
socket.emit("message", payload);
}
and here is the component I am passing
<Chat sendUsingSocket={this.sendUsingSocket} />
And here is my Component did mount
componentDidMount() {
const token = localStorage.getItem("Auth");
const userInfo = JSON.parse(localStorage.getItem("getUserInfoFromLocalStorage"));
const user_id = userInfo._id
if(token !== undefined){
socket.emit("workspace_room_join",{
workspace_id:user_id,
token:token
})
socket.on("workspace_room_join",(data) => {
})
}
socket.on("get_user_room", (data) => {
this.props.actions.savingRoomId(data)
})
socket.on("room_leave", () => {
socket.emit("room_join", {
room_id: this.props.socket_details.room_id,
})
})
socket.on("get_user_room", (data) => {
socket.emit("room_join", {
room_id: data.room_id,
})
});
socket.on("message",(data) => {
const message_details = data.chatData
this.setState({
listen_messages:message_details
})
})
localStorage.setItem('workspace_id',this.props.match.params.id)
this.props.actions.getByWorkspaceId({ id: this.props.match.params.id });
let {actions} = this.props;
actions.fetchChannelList()
actions.fetchUserlist()
}
I am unable to send messages, how to fix that?
In my app, users are able to add a loved one, like so:
addLovedOne(event) {
const {
lovedOne,
} = this.state;
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
db.addLovedOne(user.uid, lovedOne)
.then(() => {
this.setState({ lovedOne: '' });
this.refreshLovedOnes();
})
.catch(error => {
this.setState(byPropKey('error', error));
});
} else {
unsubscribe();
}
});
event.preventDefault();
}
Naturally, users are able to remove loved ones, like so:
removeLovedOne(event) {
const lovedOne = event.target.id;
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
const ref = firebase.database().ref(`users/${user.uid}/lovedOnes`);
const removeLovedOne = ref.orderByChild('lovedOne').equalTo(lovedOne);
removeLovedOne.on('value', (snapshot) => {
const lovedOneId = snapshot.node_.children_.root_.key;
db.removeLovedOne(user.uid, lovedOneId, lovedOne)
.then(() => {
this.refreshLovedOnes();
})
.catch(error => {
this.setState(byPropKey('error', error));
});
});
} else {
unsubscribe();
}
});
}
Here is what the queries look like:
export const addLovedOne = (userId, lovedOne) => (
db.ref(`users/${userId}/lovedOnes`).push({
lovedOne,
})
);
export const removeLovedOne = (userId, lovedOneKey) => (
db.ref(`users/${userId}/lovedOnes/${lovedOneKey}/lovedOne`).remove()
);
Here is what my schema looks like:
Any idea why I'm not able to add a loved one with the same name after removing it without refreshing the page?