Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

UI not re-rendering on state update using custom hook

I use useState in my custom React hook useGame and I was pretty sure that updating state in the custom hook would trigger re-rendering of every component using the hook but it turned out it doesn’t work this way

useGame hook

export const useGame = () => {
    const [stage, setStage] = useState(STAGE.START);
    const [minValue, setMinValue] = useState(DEFAULT_MIN);
    const [maxValue, setMaxValue] = useState(DEFAULT_MAX);
    const [number, setNumber] = useState(generateRandomNumberInRange(minValue, maxValue));

    const generateNumber = () => {
        const newNumber = generateRandomNumberInRange(minValue, maxValue);
        setNumber(newNumber);
    };

    return { stage, setStage, number, generateNumber };
};

Game component

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

export const Game = () => {
    const { stage } = useGame();

    return (
        <div style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center" }}>
            {(() => {
                switch (stage) {
                    case STAGE.START:
                        return <Start />;

                    case STAGE.PLAYING:
                        return <Playing />;

                    case STAGE.FINISH:
                        return <Finish />;

                    default:
                        return null;
                }
            })()}
        </div>
    );
};

Start component

export const Start = () => {
    const { setStage } = useGame();

    const handleClick = () => {
        setStage(STAGE.PLAYING);
    };

    return (
        <>
            <button onClick={handleClick}>Start game</button>
        </>
    );
};

I was sure that on handleClick it would update state stage in useGame hook, Game component would re-render and since the stage had changed it would render Playing component this time. But it doesn’t work this way. Could you please explain me what I am doing wrong and how to fix my code and make it work?

>Solution :

The useGame() calls in <Game /> and <Start /> aren’t related — they will both have their own states. React doesn’t exactly know that your useGame hook exists; it only sees that while rendering the <Game /> component (i.e. calling the Game function), useState gets called four times, and while rendering the <Start /> component (again, that is calling the Start function), useState gets called four times too. React can keep track of the eight state values by knowing where the <Game /> and <Start /> components exist in its tree model and combining that information with the order of the useState calls.

  • Game()
    • useGame() (React doesn’t see this call)
      • useState(STAGE.START) (React sees this) — State #0
      • useState(DEFAULT_MIN) (React sees this) — State #1
      • useState(DEFAULT_MAX) (React sees this) — State #2
      • useState(generate…) (React sees this) — State #3
  • <Start />
    • useGame() (React doesn’t see this call)
      • useState(STAGE.START) (React sees this) — State #4
      • useState(DEFAULT_MIN) (React sees this) — State #5
      • useState(DEFAULT_MAX) (React sees this) — State #6
      • useState(generate…) (React sees this) — State #7

To solve this, you’ll either need to move the state up (to a common ancestor component for <Game /> and <Start /> which will then pass the states and setters down as props or as a context value) or use an external state manager like Zustand, Redux, MobX etc.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading