Skip to content
Advertisement

React- Props don’t update when changing their state through the parent

The props on the ‘GameState’ component do not update correctly after changing their state from, they are always one iteration behind what the actual value of the state is as shown in the GIF and the sate is always one iteration behind when I try console.logging it too

enter image description here

import GameInfo from './components/GameInfo';
import GameState from './components/GameState';
import InputField from './components/InputField';
import StartButton from './components/StartButton';
import TheWord from './components/TheWord';
import WordsBox from './components/WordsBox';

function App() {
  const [currentDifficulty, setCurrentDifficulty] = useState({
    time: 7,
    wordCount: 15,
  });

  const changeDifficultyHandler = (difficulty) => {
    setCurrentDifficulty(difficulty);
  };

  return (
    <div>
      <header>
        Type Master
      </header>
      <main>
        <GameInfo onChangeDifficulty={changeDifficultyHandler} />
        <TheWord />
        <InputField />
        <StartButton />
        <WordsBox />
        <GameState difficulty={currentDifficulty} />
      </main>
    </div>
  );
}

export default App;
import React from 'react';

const GameState = (props) => {
  return (
    <div>
      <div>Time Left: {props.difficulty.time} Seconds</div>
      <div>Score: 0 From {props.difficulty.wordCount}</div>
    </div>
  );
};

export default GameState;

expected values:

  const levels = {
    Easy: {
      time: 7,
      wordCount: 15,
    },
    Normal: {
      time: 5,
      wordCount: 25,
    },
    Hard: {
      time: 3,
      wordCount: 30,
    },
  };

Code at the GameInfo component:

import { useState } from 'react';

const GameInfo = (props) => {
  const levels = {
    Easy: {
      time: 7,
      wordCount: 15,
    },
    Normal: {
      time: 5,
      wordCount: 25,
    },
    Hard: {
      time: 3,
      wordCount: 30,
    },
  };

  const [difficulty, setDifficulty] = useState(levels.Easy);

  const changeDifficultyHandler = (event) => {
    setDifficulty(levels[event.target.value]);
    props.onChangeDifficulty(difficulty);
  };
  return (
    <div>
      You Are Playing On The{' '}
      <span>
        [
        <select onChange={changeDifficultyHandler}>
          <option value='Easy'>Easy</option>
          <option value='Normal'>Normal</option>
          <option value='Hard'>Hard</option>
        </select>
        ]
      </span>{' '}
      Difficulity & You Have{' '}
      <span className='text-main font-poppins font-bold'>
        [ {difficulty.time} ]
      </span>{' '}
      Seconds To Type The Word.
    </div>
  );
};

export default GameInfo;

Advertisement

Answer

Set state is async, so in changeDifficultyHandler, difficulty is still referencing the old value because it hasn’t updated yet. A simple fix would be changing props.onChangeDifficulty(difficulty) to props.onChangeDifficulty(levels[event.target.value]).

That said, storing the same state in two places isn’t best practice. Why not just keep the state in App and pass it to GameInfo as a prop like <GameInfo onChangeDifficulty={changeDifficultyHandler} difficulty={currentDifficulty} />?

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement