我使用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-Hook实现这一目标?
几乎没有什么能够大大提高性能:
memo()
const MemoizedCell = memo(Cell);
/*...*/
<MemoizedCell
/*...*/
/>
<Cell />
你正在传递cell={[i, j]}
- 它每次调用它时都会创建新的数组(!),这意味着Cell的道具已被更改 - 为什么它不再渲染呢?
与传递updateBoard={updateBoard}
相同 - 每次<App />
呈现时,您都在创建新功能。你需要记住它并在功能中使用旧状态。
const updateBoard = useCallback(
(cell, nextState) => {
setBoard(oldBoard => {
let tempBoard = [...oldBoard];
tempBoard[cell[0]][cell[1]] = nextState;
return tempBoard;
});
},
[setBoard]
);
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);