Проблема с реагирующими крючками при сбросе состояния

#reactjs #react-hooks #use-effect

Вопрос:

Я пытаюсь разработать игру в крестики — нолики с использованием React и застрял на базовом шаге, т. Е. Я хочу, чтобы первый ход был X, а следующий-O и так далее.

У меня есть приведенный ниже код. Итак, я пытаюсь инициализировать состояние «данные» (что должно быть установлено) сначала на X, а затем установить состояние «Следующий выбор» в обратном порядке с помощью:

 nxtChoice = (data === "X") ? "O" : "X";
setNextChoice(nxtChoice);
 

Теперь, похоже, проблема в том, что квадратный компонент снова монтируется, а затем состояние «Первое перемещение» устанавливается в значение true каждый раз, когда возникает проблема, т. Е. Невозможность переключения между X и O.

В чем логическая проблема с приведенным выше кодом и как я могу не сбрасывать firstMove каждый раз?

 function Square(props) {
  const [firstMove, setFirstMove] = useState(true);
  let [nextChoice, setNextChoice] = React.useState("X");
  let [data, setData] = React.useState("");

  useEffect(() => {
    if (data !== "") {
      nxtChoice = (data === "X") ? "O" : "X";
      setNextChoice(nxtChoice);
    }
  }, [data]);

  const squareClicked = () => {
    let nxtChoice = firstMove ? "X" : nextChoice;
    setData(nxtChoice);
    setFirstMove(false);
  };

  return (
    <div className="square" style={squareStyle} onClick={squareClicked}>
      {data}
    </div>
  );
}

class Board extends React.Component {
  render() {
    return (
      <div style={containerStyle} className="gameBoard">
        <div id="statusArea" className="status" style={instructionsStyle}>
          Next player: <span>X</span>
        </div>
        <div id="winnerArea" className="winner" style={instructionsStyle}>
          Winner: <span>None</span>
        </div>
        <button style={buttonStyle}>Reset</button>
        <div style={boardStyle}>
          <div className="board-row" style={rowStyle}>
            <Square row={"1"} column={"1"} />
            <Square row={"1"} column={"2"} />
            <Square row={"1"} column={"3"} />
          </div>
          <div className="board-row" style={rowStyle}>
            <Square row={"2"} column={"1"} />
            <Square row={"2"} column={"2"} />
            <Square row={"2"} column={"3"} />
          </div>
          <div className="board-row" style={rowStyle}>
            <Square row={"3"} column={"1"} />
            <Square row={"3"} column={"2"} />
            <Square row={"3"} column={"3"} />
          </div>
        </div>
      </div>
    );
  }
}
 

Код также можно увидеть на
https://codesandbox.io/s/rough-glade-c1ssw?file=/src/App.js:1307-3349

Комментарии:

1. Вы заметили, что некоторые переменные в вашем примере не определены, возможно, вам следует заранее исправить ошибки lint

2. да, планируйте сделать это во время рефакторинга всего кода…

Ответ №1:

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

Для того, чтобы игра работала, эти состояния должны быть перенесены в Board компонент и переданы каждому из Square компонентов.

Комментарии:

1. Итак, должен ли мыслительный процесс быть похож на то, что состояние всегда должно находиться на самом верху иерархии и стекать вниз к дочерним компонентам…что-то вроде DDAU ? Любое оправдание или обоснование того же было бы действительно полезно…

2. Если вы хотите, чтобы ваши компоненты совместно использовали этот единственный источник информации, то да.

Ответ №2:

Существует так много проблем…

Главное из них заключается в том, что состояние игры хранится в квадратах, а не в компоненте приложения.