0

This is my GameContext file:

import { createContext } from "react";

export const GameContext = createContext(null)

In my App.js, I initialised all the values I wish to wrap my context with so that all other child components can use it:

  const gameContextValue = {
    isGameStarted,
    setGameStarted,
    isPlayerTurn,
    setPlayerTurn,
    roomId,
  };

  return (
    <GameContext.Provider value={gameContextValue}>
      <BrowserRouter>
        <Routes>
          <Route path="/register" element={<Register />} />
          <Route path="/login" element={<Login />} />
          <Route path="/" element={<JoinGame />} />
          <Route path="/game" element={<Game />} />
        </Routes>
      </BrowserRouter>
    </GameContext.Provider>
  );
}

Then,I use useContext() to use these values in my child component:

 const {
    isGameStarted,
    setGameStarted,
    isPlayerTurn,
    setPlayerTurn,
    roomId,
  } = useContext(GameContext);

const Game = () => {
  const handleGameStart = () => {
      setGameStarted(true);
      console.log("value of isGameStarted: ", isGameStarted)   //shows false
      if (start) {
        setPlayerTurn(true);
      } else {
        setPlayerTurn(false);
      }
    });
  };
}

  useEffect(() => {
    handleGameUpdate();
    handleGameStart();
  }, []);

Why does my useState updates not work? I'm not sure what i'm doing wrong...I would really appreciate any advice (been staring at my code for 2 hrs to no avail...)

  • React state updates are not immediately processed, so logging the state value immediately after enqueueing the update will still have the current state value from the current render cycle. – Drew Reese Oct 01 '22 at 05:56

1 Answers1

-1

Your value is probably set correctly. The issue is you are logging immediately after the set state. React does not immediately update the value, it is flushed later.

If you log in render you will see it is working.

See: https://beta.reactjs.org/apis/react/useState#ive-updated-the-state-but-logging-gives-me-the-old-value

 const {
    isGameStarted,
    setGameStarted,
    isPlayerTurn,
    setPlayerTurn,
    roomId,
  } = useContext(GameContext);

const Game = () => {
  const handleGameStart = () => {
      setGameStarted(true);
      if (start) {
        setPlayerTurn(true);
      } else {
        setPlayerTurn(false);
      }
    });
  };
}

  useEffect(() => {
    handleGameUpdate();
    handleGameStart();
  }, []);


console.log("value of isGameStarted: ", isGameStarted) // This is where you need to log. 
adsy
  • 8,531
  • 2
  • 20
  • 31
  • Hi, my handleGameStart function is actually in a useEffect hook, so I thought it will run everytime the Game component re-renders, and hence update the state. Am I supposed to add a ```render()``` inside the ```handleGameStart```? –  Oct 01 '22 at 05:26
  • Im not sure why I was downvoted, with your code, you absolutely will not see the new value with the log in that position. You are correct it runs when a rerender happens, however when you call `setGameStarted` or `setPlayerTurn`, the state value is actually updated a fraction of a second later *on the next render*, which is *after* the console logs the value. You just need to log in a different place, i.e. outside the hooks entirely. I will edit answer to outline. With the log line here, it will execute every time the component rerenders, and so you will capture that "next render". – adsy Oct 01 '22 at 15:14
  • Putting it another way, when you do a state update you are not actually saying "change this value immedietely". It tells react "you need to render this component again against this new state", so your update is "queued". It actually happens after all the handlers are finished. – adsy Oct 01 '22 at 15:18
  • As for what the "render" method is. In class components it would be `render()` but in the newer form of components like yours the render method is literally the component method body. – adsy Oct 01 '22 at 15:20