Реагировать - Использование componentDidUpdate для обновления состояния на основе данных, переданных из другой функции - PullRequest
0 голосов
/ 25 сентября 2018

Я изучаю React и работаю над приложением Джона Конвея Game of Life.У меня есть 2D-массив, определенный в состоянии / конструкторе, который создает игровую доску из квадратов.У меня есть функция с именем isSquareAlive, которая обрабатывает, является ли конкретный квадрат в сетке «живым» в смысле Игры Жизни, и обновляет квадраты и устанавливает их как живые, если пользователь нажимает на них.У меня также есть другая функция под названием selectBoardSize, которая позволяет пользователю нажимать кнопку и настраивать размер доски.

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

  componentDidMount = () => {
    const data = this.state.board;
    // Creates random decimal number between 0 and 1
    const startingBoard = data.map(a => a.map(Math.random));
    // Rounds decimal numbers to either 0 or 1 so the grid can display whether the cell is alive or dead
    const rounded = startingBoard.map(a => a.map(Math.round));

    this.setState({
       board: rounded
    });
  }

Это прекрасно работает.Если пользователь пытается настроить размер доски с помощью selectBoardSize, я хочу изменить размер доски, а затем снова заполнить ее случайными «живыми» ячейками.Вот selectBoardSize:

  // Allows user to click button and change size of game board
  selectBoardSize = (width, height) => {
    this.setState({
      boardHeight: height,
      boardWidth: width,
      board: Array(this.state.boardHeight).fill(0).map(_ =>
              Array(this.state.boardWidth).fill(0))
    });
      {/*this.onChangeBoardSize(width, height);*/}
  }

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

Вот мой componentDidUpdate:

  // Attempts to fill board with random alive squares when user resizes the size of the board via onClick/selectBoardSize()
  componentDidUpdate = (prevProps, prevState) => {
    console.log('PrevState is : ' + prevProps, prevState);

    // Attempts to update board height and width and then populate board with random "alive" squares
    if(this.state.boardWidth !== prevState.boardWidth) {
      if(this.state.boardHeight !== prevState.boardHeight) {
        // Console.log runs, if statements equate to true when user resizes board
        console.log('Nested if statements in componentDidUpdate triggered');

        const boardWidth = this.state.boardWidth;
        const boardHeight = this.state.boardHeight;
        const data = this.state.board;
        // Creates random decimal number between 0 and 1
        const startingBoard = data.map(a => a.map(Math.random));
        // Rounds decimal numbers to either 0 or 1 so the grid can display whether the cell is alive or dead
        const rounded = startingBoard.map(a => a.map(Math.round));

        this.setState({
          boardWidth: boardWidth,
          boardHeight: boardHeight,
          board: rounded
        })
      }
    }
  }

Доска успешно меняет размеры, когда пользователь нажимает кнопки, чтобы изменить ее размер, но не генерирует случайные«живые» квадраты, как и должно быть.Он просто изменяет высоту и ширину доски, но доска пуста.

Как я могу использовать componentDidUpdate, чтобы заполнить игровое поле случайными «живыми» ячейками при изменении его размера (аналогично тому, что он делаетпри первоначальной установке, но подходящего размера при изменении размеров платы).componentDidUpdate правильный подход?Является ли это проблемой с асинхронностью setState?

Я уверен, что я обдумываю это.

Вы можете проверить код на codesandbox .

1 Ответ

0 голосов
/ 25 сентября 2018

Вам не нужно использовать componentDidUpdate для этого, но об этом позже.

Это не работает, потому что вы (правильно, кстати) завернули свой код componentDidMount вна два условия, чтобы проверить, изменились ли boardWidth AND boardHeight.Проблема в том, что высота никогда не меняется, поэтому она никогда не достигает этой части кода.

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

Вот что, как я понимаю, вы хотите делать каждый раз, когда пользователь меняет размер:

  • Создайте новую доску на основе желаемой ширины и высоты;
  • Заполните ее случайными живыми квадратами;

Вам нужна только эта функция onChangeBoardSize с небольшим изменением.Обратите внимание, что вам не нужно извлекать доску из состояния, потому что она будет устаревшей со старой шириной и высотой;

onChangeBoardSize = (width, height) => {
  // Recreate board with new width and height values
  const data = Array(height)
    .fill(0)
    .map(_ => Array(width).fill(0));
  // Creates random decimal number between 0 and 1
  const startingBoard = data.map(a => a.map(Math.random));
  // Rounds decimal numbers to either 0 or 1 so the grid can display whether the cell is alive or dead
  const rounded = startingBoard.map(a => a.map(Math.round));

  this.setState({
    boardHeight: height,
    boardWidth: width,
    board: rounded
  });
};

Пример Codesandbox

Совет: Остерегайтесь слишком большого количества последовательных изменений состояния.Всегда предпочитайте делать все сразу, чем последовательно запускать setState.Специально внутри реагируют методы жизненного цикла

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...