Valery Mbele
Valery Mbele

Reputation: 13

React Hook (usestate ) not working when combined with socket io

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();
        //
      }, []);

console-capture

Please can you help me ? i didn't find similar case . Thanks.

Upvotes: 0

Views: 3429

Answers (4)

Sahanur Alom laskar
Sahanur Alom laskar

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

shahin davoodi
shahin davoodi

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

CertainPerformance
CertainPerformance

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

Nicholas Tower
Nicholas Tower

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

Related Questions