首页 > 解决方案 > 无法使用备忘录解决浪费的重新渲染

问题描述

我最近开始学习 React,我正在创建一个 2048 游戏。现在,每当用户执行移动时,我都会对网格进行某些更改,从而更新状态。然而,随着每次后续按键,网格重新渲染的次数呈指数增长并在某个点后冻结,即使状态(网格的值)没有变化。即使在使用 React.memo 后问题仍然存在。我该如何解决这些不需要的重新渲染,为什么会发生?

import React, { useState, useEffect } from "react";
import Cell from "./Cell";
import "./Game.css";

let permittedKeys = [
  "ArrowUp",
  "KeyW",
  "ArrowRight",
  "KeyD",
  "ArrowDown",
  "KeyS",
  "ArrowLeft",
  "KeyA",
];

const boardSize = 4;

function Game() {
  const [grid, setGrid] = useState();

  console.log("re-rendering grid", grid);
  //creating a 4x4 board when component mounts
  useEffect(() => {
    const board = getBoard(boardSize);
    setGrid(board);
  }, []);

  //function that renders all the 4x4 cells
  // CORRECTION - Give every cell a key
  const renderCells =
    grid &&
    grid.map((row, i) => row.map((col, j) => <Cell key={i*boardSize+j} value={grid[i][j]} />));

  //check if a key is pressed
  document.addEventListener("keydown", (e) => {
    //If pressed key is not a valid game control key ignore the keydown event
    if (permittedKeys.indexOf(e.code) === -1) return;

    //Else
    if (grid) setGrid(performMove(e.code, [...grid], boardSize));
  });

  return <div className="board">{renderCells}</div>;
}

const performMove = (pressedKey, board, boardSize) => {
  //Move cells in pressedKey-direction till they hit another block
  //Eg:When left key is pressed
  //256 empty 256 64 becomes
  //256 256 64 empty
  for (let i = 0; i < boardSize; ++i) {
    const newRow = [];
    let count = 0;

    for (let j = 0; j < boardSize; ++j)
      if (board[i][j]) {
        newRow.push(board[i][j]);
        ++count;
      }
    while (count !== boardSize) {
      ++count;
      if (pressedKey === permittedKeys[6] || pressedKey === permittedKeys[7])
        newRow.push(0);
      else if (
        pressedKey === permittedKeys[2] ||
        pressedKey === permittedKeys[3]
      )
        newRow.unshift(0);
    }
    board[i] = newRow;
  }
  return board;
};

//generate the next cell after the player performs a move
function generateNext() {
  return Math.random() < 0.9 ? 2 : 4;
}

function getBoard(boardSize) {
  const board = [];
  for (let i = 0; i < boardSize; ++i) {
    const row = [];
    for (let j = 0; j < 4; ++j) row.push(0);
    board.push(row);
  }
  //generating two random starting cells
  let i1 = Math.floor(Math.random() * boardSize);
  let j1 = Math.floor(Math.random() * boardSize);
  let i2, j2;
  do {
    i2 = Math.floor(Math.random() * boardSize);
    j2 = Math.floor(Math.random() * boardSize);
  } while (i1 === i2 && j1 === j2);

  board[i1][j1] = generateNext();
  board[i2][j2] = generateNext();

  return board;
}

export default React.memo(Game);

标签: javascriptreactjsstaterenderingmemo

解决方案


推荐阅读