我正在创建一个 HTML 元素网格,每个元素对应一个“节点”反应组件,并保存在父“可视化器”反应组件中。代码如下所示。
在 Visualiser 父组件中使用 useState 创建一个包含每个节点数据的 2D 对象数组。当使用作为道具提供给子节点的回调函数单击节点子组件时,此列表中有关特定节点的数据会一次更新一个。如果用户当前按住鼠标并将鼠标悬停在节点上,节点数据也可能发生变化,这是使用简单的 mousePressed useState 实现的。这用于在网格上创建类似绘画的效果,但变得非常滞后。
我知道每当 gridData 更新时,React 都会重新渲染每个 Node 组件,因为即使 gridData 中只有一个对象发生了变化,React 也会将其视为整个 gridData 发生变化。
我尝试将 Node 子组件更改为 React.memo HOC,然后在我的三个鼠标单击方法上使用 useCallback 挂钩,以确保 React 将记住它提供的数据道具和函数回调。我还尝试手动将 React.memo isEquals 比较更改为仅对给定的 nodeData 进行浅比较。
这两种方法都只导致我单击更新的节点(有点),但我不能再一次在多个节点中拖动到“绘制”,并且还有奇怪的行为,鼠标单击回调不再正确更改gridData 或 mousePressed 的状态,这让我觉得有更合适的方法来做到这一点。
我知道我需要在某处使用 react 的 memoization 来提高性能,我只是不知道如何或在哪里。任何帮助将非常感激!!
可视化组件代码:
export default Visualiser = () => {
const [gridData, updateGridData] = React.useState(createGridData())
const [mousePressed, updateMousePressed] = React.useState(false)
// Toggles the 'wall' property for a Node at row, col
const placeWallInGrid = (row, col) => {
const newGrid = [...gridData]
const wallNode = newGrid[row][col]
const newNode = {
...wallNode, isWall: !wallNode.isWall,
}
newGrid[row][col] = newNode
return newGrid
}
// Possible useCallback functions that are called in child <Node /> components
const handleMouseDown = (row, col) => {
updateGridData(placeWallInGrid(row, col))
updateMousePressed(true)
}
const handleMouseEnter = (row, col) => {
if (mousePressed) {
updateGridData(placeWallInGrid(row, col))
}
}
const handleMouseUp = () => {
updateMousePressed(false)
}
// Main render - possible useMemo?
return (
<div className="grid">
{gridData.map((rowData, rowIndex) => {
return (
<div key={rowIndex}>
{rowData.map((node, colIndex) => {
return (
<Node
key={nodeIndex}
nodeData={node}
onMouseDown={() => {handleMouseDown(rowIndex, colIndex)}}
onMouseEnter={() => {handleMouseEnter(rowIndex, colIndex)}}
onMouseUp={() => {handleMouseUp()}}
/>
)
})}
</div>
)
})}
</div>
)
}
创建二维节点数据数组:
const createNode = (row, col) => {
return ({
row,
col,
isWall: false,
})
}
const createGridData = () => {
const grid = []
for (let row = 0; row < Constants.NUM_ROWS; row++) {
const currentRow = []
for (let col = 0; col < Constants.NUM_COLS; col++) {
currentRow.push(createNode(row, col))
}
grid.push(currentRow)
}
return grid
}