我正在尝试创建一个节点网格,在单击/拖动它们时会更新。我遇到了一个怪异的React State,在该状态下的代码运行后,该状态正在更新。
预期行为:
实际行为
我知道状态是异步的,但是不确定继续进行的确切原因/问题/解决方案。如果我要使用UseEffect,则不确定如何将参数传递给下一个函数。
代码如下:
import React, { useEffect, useState } from 'react';
import Node from './Node'
import './Grid.css';
const rectDiameter = 25
const gridHeightRatio = 0.9
const Grid: React.FC = () => {
const gridHeight: number = Math.floor(window.innerHeight * gridHeightRatio)
const gridWidth: number = window.innerWidth
const numX: number = Math.floor(gridHeight / rectDiameter)
const numY: number = Math.floor(gridWidth / rectDiameter)
const tempGrid: number[][] = [...Array(numX)].map(() => Array(numY).fill(0));
const [grid, setGrid] = useState(tempGrid)
const [isMousePressed, setMousePressed] = useState(false)
const [nodeTypePointer, setNodeTypePointer] = useState(0)
useEffect(() => {
console.log('Use Effect', nodeTypePointer)
}, [nodeTypePointer])
// Hacky el.ID to workaround React performance until I know how to do it better
const paintNode = (x: number, y: number) => {
const el = document.getElementById(`${x}-${y}`)
if (!el) return
if (nodeTypePointer === 0) {
el.classList.add("node-wall")
} else {
el.classList.remove("node-wall")
}
}
const updateGridPosition = (x: number, y: number) => {
const newValue = nodeTypePointer === 0 ? 1 : 0
let newGrid: number[][] = grid
newGrid[x][y] = newValue
setGrid(newGrid)
}
const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>, x: number, y: number) => {
console.log('Node pointer type Before', nodeTypePointer)
setNodeTypePointer(grid[x][y])
console.log('Node pointer type After', nodeTypePointer)
setMousePressed(true)
console.log('Before updated Grid', grid[x][y])
updateGridPosition(x, y)
console.log('After updated Grid', grid[x][y])
paintNode(x, y) // <------------- Uses nodeTypePointer
}
const handleMouseUp = (event: React.MouseEvent<HTMLDivElement>, x: number, y: number) => {}
const handleHover = (event: React.MouseEvent<HTMLDivElement>, x: number, y: number) => {
if (!isMousePressed) return
updateGridPosition(x, y)
paintNode(x, y)
}
return (
<div className='gridContainer' >
{
grid.map((row: number[], i: number) =>
row.map((val: number, j: number) =>
<Node
x={i}
y={j}
d={rectDiameter}
key={`${i}-${j}`}
state={val}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
onHover={handleHover} />
)
)
}
</div>
);
}
export default Grid
在理解问题和建议解决方案方面的任何帮助将不胜感激!
答案 0 :(得分:0)
状态更改是异步的(组件更改和挂接更改)。因此,在您致电paintNode
时,您的状态尚未更新。我可以通过两种方法来解决它。一种方法是将呼叫paintNode
放在nodeTypePointer
的{{1}}中,如下所示:
useEffect
但是这意味着您需要将单击的 useEffect(() => {
paintNode(x,y);
}, [nodeTypePointer])
和x
存储在一些标准变量中,因为您将无法直接将它们传递给y
。另一种方法(也许是一种更好的方法,因为我不是状态改变的忠实拥护者)在useEffect
函数期间将x / y直接传递到paintNode
中:>
handleMouseDown
尽管看起来paintNode(x, y, grid[x][y])
也需要x / y,所以也许最好保存原始点击状态,然后使用updateGridPosition
单击该节点后,它将完成所有需要的操作。一切都取决于该功能的最终外观。
但是,是的,导致您的错误的原因是状态更改是异步的,因此在您致电useEffect
时尚未更新