1

我正在创建一个 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
}
4

0 回答 0