javascriptsocket.iocomponentshookuse-state

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.


Solution

  • 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.