使用 React-Hooks,如果从 Array.map 创建的组件之一更改状态,如何防止其重新渲染?



我使用 array.map 创建了一个组件网格。使用 console.log我能够看到每当其中一个组件更改状态时,每个组件都会重新渲染。当我有一个 50x50 的网格时,这变得明显很慢。

import React, { useState } from 'react';
function Cell({ cell, cellState, updateBoard }) {
  console.log('cell rendered')
  const CellStyle = {
    display: 'inline-block',
    width: '10px',
    height: '10px',
    border: '1px green solid',
    background: cellState ? 'green' : 'purple'
  };
  function handleClick(e) {
    updateBoard(cell, !cellState)
  }
  return (
    <span
      style={CellStyle}
      onClick={handleClick}
    />
  )
}
function App() {
  console.log('board rendered')
  const initialState = new Array(10).fill().map(() => new Array(10).fill(false));
  let [board, setBoard] = useState(initialState);
  function updateBoard(cell, nextState) {
    let tempBoard = [...board];
    tempBoard[cell[0]][cell[1]] = nextState;
    setBoard(tempBoard)
  }
  return (
    <div style={{ display: 'inline-block' }}>
      {board.map((v, i, a) => {
        return (
          <div
            key={`Row${i}`}
            style={{ height: '12px' }}
          >
            {v.map((w, j) =>
              <Cell
                key={`${i}-${j}`}
                cell={[i, j]}
                cellState={board[i][j]}
                updateBoard={updateBoard}
              />
            )}
          </div>
        )
      }
      )}
    </div>
  )
}
export default App;

当我单击其中一个组件时,我希望更新父状态,并且单击的组件更新并重新渲染。由于其余组件没有更改,因此我不希望其他组件重新渲染。如何使用 React-Hooks 完成此操作?

很少有

事情可以大大提高性能:

  1. 使用memo()
const MemoizedCell = memo(Cell);
/*...*/
<MemoizedCell 
  /*...*/
/>
  1. 不会每次都向<Cell />传递新的引用

您正在传递cell={[i, j]} - 每次调用它时它都会创建新的数组(!(,这意味着单元格的道具已更改 - 为什么它不会再次渲染呢?

与传递updateBoard={updateBoard}相同 - 每次渲染时都会创建新函数<App />。您需要记住它并在函数中使用旧状态。

  const updateBoard = useCallback(
    (cell, nextState) => {
      setBoard(oldBoard => {
        let tempBoard = [...oldBoard];
        tempBoard[cell[0]][cell[1]] = nextState;
        return tempBoard;
      });
    },
    [setBoard]
  );
  1. 您正在为每个渲染创建initialState - 将其移动到上方(外部(<App />或将其作为函数在useState内部创建(并使用const而不是此处的let(。
const [board, setBoard] = useState(() =>
  new Array(10).fill().map(() => new Array(10).fill(false))
);

最终解决方案:

import React, { useState, memo, useCallback } from "react";
import ReactDOM from "react-dom";
function Cell({ i, j, cellState, updateBoard }) {
  console.log(`cell ${i}, ${j} rendered`);
  const CellStyle = {
    display: "inline-block",
    width: "10px",
    height: "10px",
    border: "1px green solid",
    background: cellState ? "green" : "purple"
  };
  function handleClick(e) {
    updateBoard([i, j], !cellState);
  }
  return <span style={CellStyle} onClick={handleClick} />;
}
const MemoizedCell = memo(Cell);
function App() {
  console.log("board rendered");
  const [board, setBoard] = useState(() =>
    new Array(10).fill().map(() => new Array(10).fill(false))
  );
  const updateBoard = useCallback(
    (cell, nextState) => {
      setBoard(oldBoard => {
        let tempBoard = [...oldBoard];
        tempBoard[cell[0]][cell[1]] = nextState;
        return tempBoard;
      });
    },
    [setBoard]
  );
  return (
    <div style={{ display: "inline-block" }}>
      {board.map((v, i, a) => {
        return (
          <div key={`Row${i}`} style={{ height: "12px" }}>
            {v.map((w, j) => (
              <MemoizedCell
                key={`${i}-${j}`}
                i={i}
                j={j}
                cellState={board[i][j]}
                updateBoard={updateBoard}
              />
            ))}
          </div>
        );
      })}
    </div>
  );
}
export default App;
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

相关内容

  • 没有找到相关文章

最新更新