Проблема с реакцией useState отстает на один шаг - PullRequest
1 голос
/ 11 июля 2020

Я пытаюсь преобразовать Javascript игру, которую я узнал от Udemy, в приложение для реагирования. Очевидно, оно называется Pig-Game. вы можете бросить кубик и добавить его значение в свой банк, пока не наберете 1, а затем наступит очередь вашего оппонента бросить кубик. вы можете сохранить значение и добавить его к своей сумме, прежде чем проиграть ход. Я написал функцию для «btn-roll», чтобы обновить кубик и добавить его значение в мои состояния. вот код (исключая ненужные части):

const App = () => {

  const [dice, setdice] = useState(null);
  const [current, setCurrent] = useState(0);
  const [activePlayer, setactivePlayer] = useState(0);

  const diceHandler = () => {
    if (dice !== 1) {
      setdice(() => {
        const _dice = (Math.floor(Math.random() * 6) + 1);
        setCurrent(current + _dice);
        console.log(_dice);
        return _dice;
      }
      );
    } else {
      activePlayer === 0 ? setactivePlayer(1) : setactivePlayer(0);
      setdice(() => {
        setCurrent(0);
        return null;
      })
    }
  }

 return (

      <button className="btn-roll" onClick={diceHandler}><i className="ion-ios-loop"></i>Roll dice</button>
      {dice ?
        <img src={require(`./dice-${dice}.png`)} alt="Dice" className="dice" /> :
        <></>
      }
  );
} 

первая проблема заключалась в том, что «игральные кости» и «текущий» отставали на 1 шаг. каждый раз, когда я нажимал кнопку, он показывал случайное изображение игральных костей, но фактическое значение для кубиков и тока отставало на 1 шаг. Я исправил это с помощью кода, свидетелем которого вы сейчас являетесь. Теперь проблема в том, что после того, как я нажму «1», он прибавит значение к текущему, затем мне нужно щелкнуть еще раз, чтобы инициировал setCurrent (0) и переключился activePlayer. Я тоже пробовал эту функцию, но результат тот же:

  const diceHandler = () => {

    setdice(() => {
      if (dice !== 1) {
        const _dice = (Math.floor(Math.random() * 6) + 1);
        setCurrent(current + _dice);
        console.log(_dice);
        return _dice;
      } else {
        activePlayer === 0 ? setactivePlayer(1) : setactivePlayer(0);
        setdice(() => {
          setCurrent(0);
          return null;
        })
      }
    }
    );

  }

я хочу знать, есть ли лучшее решение для моей существующей функции (для обновления состояний) и почему мне нужно нажимать кнопку очередной раз. Я неправильно использую крючки? заранее спасибо

Ответы [ 2 ]

2 голосов
/ 11 июля 2020

Вы могли бы немного упростить этот logi c.

 const diceHandler = () => {
   const _dice = Math.floor(Math.random() * 6) + 1;
   
   if (_dice !== 1) {
     setCurrent(current + _dice);
     setdice(_dice);
   } else {
     setactivePlayer(activePlayer === 0 ? 1 : 0);
     setCurrent(0);
     setdice(0);
   }
 };

Обратите внимание, как тернарный оператор используется для обновления activePlayer. Использование функции обратного вызова в установщике состояния иногда необходимо, но здесь это не кажется необходимым.

1 голос
/ 11 июля 2020

Надеюсь, приведенный ниже код вам поможет!

 const App = () => {
      const [dice, setdice] = useState(null);
      const [current, setCurrent] = useState(0);
      const [activePlayer, setactivePlayer] = useState(0);

    const stateUpdater = _dice => {
      console.log(dice);
      if (dice !== 1) {
        setCurrent(current + _dice);
        console.log("dice value " + _dice);
      } else {
        console.log("Dice value is now one!", dice);
        activePlayer === 0 ? setactivePlayer(1) : setactivePlayer(0);
        setCurrent(0);
        setdice(null);
      }
    };

    const diceHandler = () => {
      let _dice = Math.floor(Math.random() * 6) + 1;
      setdice(_dice, stateUpdater(dice));
    };

    return (

     <button className="btn-roll" onClick={diceHandler}><i className="ion-ios-loop"></i>Roll dice</button>
     {dice ?
      <img src={require(`./dice-${dice}.png`)} alt="Dice" className="dice" /> :
    <></>
  }
  );
};

Функция diceHandler отвечает только за создание нового значения кубиков и обновление его до крючка.

Как только хук обновляется, будет вызван обратный вызов, и его ответственность будет заключаться в обновлении значения там, где это необходимо, и в дальнейшем продвижении игры.

Причина, по которой он не работал ранее, заключается в том, что функции setState асинхронны и имеют задержки. Вот почему значение обновленной переменной может не сразу отражаться в операторах, следующих за setState.

...