Search code examples
reactjsreact-hooksuse-statereact-state

React state is never up to date in my callback


In a react functional component, I setState from an api call. I then create an EventSource that will update the state each time an event is received.

The problem is that in the EventSource callback, the state is not updated.

My guess is, state is printed at the creation of the callback, so it can't be updated.
Is there any other way to do it ?

function HomePage() {
    const [rooms, setRooms] = useState<Room[]>([]);

    const getRooms = async () => {
        const data = await RoomService.getAll(currentPage);
        setRooms(data.rooms);
    }

    const updateRooms = (data: AddRoomPayload | DeleteRoomPayload) => {
        console.log(rooms); // rooms is always empty
        // will append or remove a room via setRooms but i need actual rooms first
    }

    useEffect(() => {
        // setState from api response
        getRooms();

        // set up EventSource
        const url = new URL(process.env.REACT_APP_SSE_BASE_URL ?? '');
        url.searchParams.append('topic', '/room');
        const eventSource = new EventSource(url);
        eventSource.onmessage = e => updateRooms(JSON.parse(e.data));
    }, [])

    ...
}

Solution

  • Try using a functional update when using setRooms like this:

    const updateRooms = (data: AddRoomPayload | DeleteRoomPayload) => {
       setRooms((rooms) => {
         if (data.type === 'add') {
           return [...rooms, data.room];
         } else if (data.type === 'remove') {
           return rooms.filter(/* ... */);
         }
       });
    }
    

    Here is a reference to the React Docs on functional updates in useState: https://reactjs.org/docs/hooks-reference.html#functional-updates

    If that doesn't work then try checking the React Developer Tools to make sure that the component's state rooms is being updated.