繁体   English   中英

使用React-Hooks,如果其中一个兄弟姐妹更改了状态,如何防止从Array.map创建的组件重新呈现?

[英]Using React-Hooks, how do I prevent a component created from Array.map from re-rendering if one of it's siblings changes state?

我已经使用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]} - 每次调用它都会创建一个新的Array(!) ,这意味着Cells的属性已更改-为什么它以后不会再次渲染?

与传递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内部useState其创建为函数(并使用const而不是let here)。
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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM