Reputation: 13
I'm going crazy. I really don't understand why the below is not working. I'm starting with react. I'm trying to fetch datas from server and load my state before rendering. Socket "fromAPI" is ok, this is only a timer. Socket "lobbyUpdate " not working , i'm fetching data from database.
import React, { useState, useEffect } from "react";
import socketIOClient from "socket.io-client";
const ENDPOINT = "http://localhost:2500";
function Lobby() {
const [response, setResponse] = useState("")
const [updates, setUpdates] = useState([])
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on("FromAPI", data => {
setResponse(data);
});
socket.on('lobbyUpdate', datas => {
console.log(updates) // Nothing
setUpdates(datas)
console.log(datas) // datas are displayed
console.log(updates) // nothing is displayed
})
// CLEAN UP THE EFFECT
return () => socket.disconnect();
//
}, []);
Please can you help me ? i didn't find similar case . Thanks.
Upvotes: 0
Views: 3429
Reputation: 1
import React, { useState, useEffect } from "react";
import socketIOClient from "socket.io-client";
const ENDPOINT = "http://localhost:2500";
function Lobby() {
const [response, setResponse] = useState("")
const [updates, setUpdates] = *4.0*([])
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on("FromAPI", data => {
setResponse(data);
});
socket.on('lobbyUpdate', datas => {
console.log(updates) // Nothing
setUpdates(datas)
console.log(datas) // datas are displayed
console.log(updates) // nothing is displayed
})
// CLEAN UP THE EFFECT
return () => socket.disconnect();
//
}, []);
Upvotes: 0
Reputation: 61
you must define your socket const inside the useEffect() it will render the useEffect hook after every socket update.
const [update,setupdate] = useState()
useEffect(()=>{
const socket = io("http://localhost:3001");
socket.on("send data", function (data_from_socket) {
setupdate(data_from_socket);
})
})
and dont forget to not to use [] in useEfect
Upvotes: 0
Reputation: 370689
Your updates
inside the useEffect
is referencing the value from the initial render, rather than the value currently being rendered. To fix it, either use refs instead of (or in addition to) state, or have the useEffect
run every time the updates change:
function Lobby() {
const [response, setResponse] = useState("")
const [updates, setUpdates] = useState([])
const socketRef = useRef();
// Create the socket
// and add the API listener:
useEffect(() => {
socketRef.current = socketIOClient(ENDPOINT);
socketRef.current.on("FromAPI", setResponse);
return () => socketRef.current.disconnect();
}, []);
useEffect(() => {
const handleLobbyUpdate = (datas) => {
console.log(updates); // this will now display the current data
setUpdates(datas);
};
socketRef.current.on('lobbyUpdate', handleLobbyUpdate);
return () => {
socketRef.current.off('lobbyUpdate', handleLobbyUpdate);
}
}, [updates]);
Remember that state setters are asynchronous, so you won't see a change in the updates
variable immediately after calling setUpdates
- you'll have to wait until the next render for the updates
to become populated.
Upvotes: 2
Reputation: 84912
Your code is working fine, you just have your log statements in places where they aren't useful.
updates
is a local const. It will never change, and that's not what setUpdates
is trying to do. The console.log statements in the useEffect will only ever be referring to the values that response
and updates
had at the time of the first render.
When you call setUpdates
, you are asking react to rerender the component. On that new render, a new local const will be created, and it will get the new value. Code in the new render can use this value, but code in the previous render can not. If you want to verify that it is rerendering with the new value, then put your log statement into the body of the component:
function Lobby() {
const [response, setResponse] = useState("")
const [updates, setUpdates] = useState([])
console.log("rendering with: ", response, updates);
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on("FromAPI", data => {
setResponse(data);
});
socket.on('lobbyUpdate', datas => {
setUpdates(datas)
})
// CLEAN UP THE EFFECT
return () => socket.disconnect();
}, []);
Upvotes: 1