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

时间:2019-04-11 20:34:23

标签: javascript reactjs react-hooks

我已经使用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 个答案:

答案 0 :(得分:2)

几乎没有什么可以大大提高性能的。

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

您正在传递cell={[i, j]}-每次调用它都会创建新数组(!),这意味着Cells的属性已被更改-为什么那时不再次渲染? / p>

与传递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而不是{{1} })。
let

最终解决方案:

const [board, setBoard] = useState(() =>
  new Array(10).fill().map(() => new Array(10).fill(false))
);