Javascript 为什么在我用React钩子调用setState之前,我的状态一直在更新?如何修复禁用的鼠标指针?
目前,我在重建dijkstras寻路可视化工具时遇到两个问题 我的代码沙盒:Javascript 为什么在我用React钩子调用setState之前,我的状态一直在更新?如何修复禁用的鼠标指针?,javascript,reactjs,Javascript,Reactjs,目前,我在重建dijkstras寻路可视化工具时遇到两个问题 我的代码沙盒: 如果单击/单击并拖动到轴网上,可以创建阻止路径的墙节点。但是,如果你点击并拖动几个节点,释放鼠标按钮并点击并拖动你结束的同一个节点,鼠标指针不知何故被禁用,并且没有注意到onMouseUp事件。结果:仍然单击鼠标-->因此即使未按下鼠标,您仍然可以在MouseOver上创建墙 以前,通过getElementById.classname添加一个类来为算法访问的节点设置动画。但是我实际上想通过传递属于状态的isvisted
getElementById.classname
添加一个类来为算法访问的节点设置动画。但是我实际上想通过传递属于状态的isvisted
属性来更新子组件中的类。但是我不明白为什么在调用setState
之前,我的在我的状态中被访问了
,或者我如何正确地执行它。当前,所有已访问的节点在返回白色之前都会立即设置动画,就好像它们未被访问一样import React, { useState, useEffect, useCallback, useRef } from "react";
import Node from "../Node/Node";
import "./PathfindingVisualizer.css";
import { dijkstra, getNodesInShortestPathOrder } from "../algorithms/dijkstras";
const START_NODE_ROW = 0;
const START_NODE_COL = 0;
const FINISH_NODE_ROW = 0;
const FINISH_NODE_COL = 3;
const TOTAL_ROWS = 5;
const TOTAL_COLS = 10;
const PathfindingVisualizer = () => {
const [nodeGrid, setNodeGrid] = useState({
grid: []
});
const mouseIsPressed = useRef(false);
useEffect(() => {
const grid1 = getInitialGrid();
setNodeGrid({ ...nodeGrid, grid: grid1 });
}, []);
const handleMouseDown = useCallback((row, col) => {
//console.log(newGrid);
setNodeGrid(prevGrid => ({
grid: getNewGridWithWallToggled(prevGrid.grid, row, col)
}));
mouseIsPressed.current = true;
//console.log(nodeGrid);
}, []);
// function handleMouseDown(row, col) {
// const newGrid = getNewGridWithWallToggled(nodeGrid.grid, row, col);
// console.log(newGrid);
// setNodeGrid({...nodeGrid, nodeGrid[row][col]= newGrid});
// }
const handleMouseEnter = useCallback((row, col) => {
//console.log(mouseIsPressed);
if (mouseIsPressed.current) {
setNodeGrid(prevNodeGrid => ({
...prevNodeGrid,
grid: getNewGridWithWallToggled(prevNodeGrid.grid, row, col)
}));
}
}, []);
const handleMouseUp = useCallback(() => {
mouseIsPressed.current = false;
}, []);
// const animateDijkstra = (visitedNodesInOrder, nodesInShortestPathOrder) => {
// for (let i = 0; i <= visitedNodesInOrder.length; i++) {
// if (i === visitedNodesInOrder.length) {
// setTimeout(() => {
// animateShortestPath(nodesInShortestPathOrder);
// }, 10 * i);
// return;
// }
// setTimeout(() => {
// const node = visitedNodesInOrder[i];
// document.getElementById(`node-${node.row}-${node.col}`).className =
// "node node-visited";
// }, 10 * i);
// }
// };
const animateDijkstra = (visitedNodesInOrder, nodesInShortestPathOrder) => {
for (let i = 0; i <= visitedNodesInOrder.length; i++) {
if (i === visitedNodesInOrder.length) {
setTimeout(() => {
animateShortestPath(nodesInShortestPathOrder);
}, 17 * i);
return;
}
setTimeout(() => {
const node = visitedNodesInOrder[i];
console.log("node", node);
console.log("state", nodeGrid);
console.log(
"before setNode",
nodeGrid.grid[node.row][node.col].isVisited
);
setNodeGrid(prevNodeGrid => ({
...prevNodeGrid,
grid: getNewGridWithVisited(prevNodeGrid.grid, node.row, node.col)
// //grid: node
}));
console.log(
"after setNode;",
nodeGrid.grid[node.row][node.col].isVisited
);
}, 17 * i);
}
};
const animateShortestPath = nodesInShortestPathOrder => {
for (let i = 0; i < nodesInShortestPathOrder.length; i++) {
setTimeout(() => {
const node = nodesInShortestPathOrder[i];
document.getElementById(`node-${node.row}-${node.col}`).className =
"node node-shortest-path";
}, 50 * i);
}
};
const visualizeDijkstra = () => {
const grid = nodeGrid.grid;
console.log(grid);
const startNode = grid[START_NODE_ROW][START_NODE_COL];
const finishNode = grid[FINISH_NODE_ROW][FINISH_NODE_COL];
const visitedNodesInOrder = dijkstra(grid, startNode, finishNode);
const nodesInShortestPathOrder = getNodesInShortestPathOrder(finishNode);
animateDijkstra(visitedNodesInOrder, nodesInShortestPathOrder);
};
//console.log(nodeGrid.grid);
//console.log(visualizeDijkstra());
return (
<>
<button onClick={visualizeDijkstra}>
Visualize Dijkstra´s Algorithm
</button>
<div className="grid">
test
{nodeGrid.grid.map((row, rowIdx) => {
return (
<div className="row" key={rowIdx}>
{row.map((node, nodeIdx) => {
const { row, col, isStart, isFinish, isWall, isVisited } = node;
return (
<Node
key={nodeIdx}
col={col}
row={row}
isStart={isStart}
isFinish={isFinish}
isWall={isWall}
isVisited={isVisited}
onMouseDown={handleMouseDown}
onMouseEnter={handleMouseEnter}
onMouseUp={handleMouseUp}
/>
);
})}
</div>
);
})}
</div>
</>
);
};
export default PathfindingVisualizer;
//----------------------------------------------------------
const getInitialGrid = () => {
const grid = [];
for (let row = 0; row < TOTAL_ROWS; row++) {
const currentRow = [];
for (let col = 0; col < TOTAL_COLS; col++) {
currentRow.push(createNode(col, row));
}
grid.push(currentRow);
}
return grid;
};
const createNode = (col, row) => {
return {
col,
row,
isStart: row === START_NODE_ROW && col === START_NODE_COL,
isFinish: row === FINISH_NODE_ROW && col === FINISH_NODE_COL,
distance: Infinity,
isVisited: false,
isWall: false,
previousNode: null
};
};
const getNewGridWithWallToggled = (grid, row, col) => {
const newGrid = grid.slice();
const node = newGrid[row][col];
const newNode = {
...node,
isWall: !node.isWall
};
newGrid[row][col] = newNode;
return newGrid;
};
const getNewGridWithVisited = (grid, row, col) => {
const newGrid = grid.slice();
const node1 = newGrid[row][col];
const newNode = {
...node1,
isVisited: true
//isVisited: !node1.isVisited
};
//console.log(newNode);
newGrid[row][col] = newNode;
return newGrid;
};
import React from "react";
import "./Node.css";
import { useCountRenders } from "../Node/useCountRenders";
const Node = React.memo(
({
col,
isFinish,
isStart,
isWall,
onMouseDown,
onMouseEnter,
onMouseUp,
row,
isVisited
}) => {
//console.log("props: col, isWall, row;", col, isWall, row);
const extraClassName = isFinish
? "node-finish"
: isStart
? "node-start"
: isWall
? "node-wall"
: isVisited
? 'node-visited'
: "";
useCountRenders();
console.log("node rerendered: row:", row, "col:", col);
return (
<div
id={`node-${row}-${col}`}
className={`node ${extraClassName}`}
onMouseDown={() => onMouseDown(row, col)}
onMouseEnter={() => onMouseEnter(row, col)}
onMouseUp={() => onMouseUp()}
/>
);
}
);
export default Node;
import React,{useState,useffect,useCallback,useRef}来自“React”;
从“./Node/Node”导入节点;
导入“/PathfindingVisualizer.css”;
从“./algorithms/dijkstras”导入{dijkstra,getNodesInShortestPathOrder};
常量开始节点行=0;
const START_NODE_COL=0;
const FINISH\u NODE\u ROW=0;
const FINISH_NODE_COL=3;
const TOTAL_ROWS=5;
const TOTAL_COLS=10;
常量路径查找可视化工具=()=>{
const[nodeGrid,setNodeGrid]=useState({
网格:[]
});
const mouseIsPressed=useRef(false);
useffect(()=>{
const grid1=getInitialGrid();
setNodeGrid({…nodeGrid,grid:grid1});
}, []);
const handleMouseDown=useCallback((行,列)=>{
//console.log(newGrid);
setNodeGrid(prevGrid=>({
网格:getNewGridWithWallToggled(prevGrid.grid,行,列)
}));
mouseIsPressed.current=true;
//console.log(nodeGrid);
}, []);
//功能手柄向下(行、列){
//const newGrid=getnewgridwithwalltogled(nodeGrid.grid,row,col);
//console.log(newGrid);
//setNodeGrid({…nodeGrid,nodeGrid[row][col]=newGrid});
// }
常量HandleMouseCenter=useCallback((行,列)=>{
//console.log(鼠标按下);
如果(鼠标按下。当前){
setNodeGrid(prevNodeGrid=>({
…prevNodeGrid,
网格:getNewGridWithWallToggled(prevNodeGrid.grid,行,列)
}));
}
}, []);
const handleMouseUp=useCallback(()=>{
mouseIsPressed.current=false;
}, []);
//常量animateDijkstra=(已访问NodesNorder、nodesInShortestPathOrder)=>{
//for(设i=0;i{
//animateShortestPath(nodesinshortestpath顺序);
//(a)10*i);
//返回;
// }
//设置超时(()=>{
//const node=visitedNodesInOrder[i];
//document.getElementById(`node-${node.row}-${node.col}`)。className=
//“已访问的节点”;
//(a)10*i);
// }
// };
常量animateDijkstra=(已访问NodesNorder、nodesInShortestPathOrder)=>{
for(设i=0;i{
animateShortestPath(nodesinshortestpath顺序);
},17*i);
返回;
}
设置超时(()=>{
const node=visitedNodesInOrder[i];
console.log(“节点”,node);
日志(“状态”,nodeGrid);
console.log(
“在setNode之前”,
nodeGrid.grid[node.row][node.col].isvisted
);
setNodeGrid(prevNodeGrid=>({
…prevNodeGrid,
网格:getNewGridWithVisited(prevNodeGrid.grid、node.row、node.col)
////网格:节点
}));
console.log(
“在setNode之后;”,
nodeGrid.grid[node.row][node.col].isvisted
);
},17*i);
}
};
常量animateShortestPath=nodesinshortestpath=>{
for(设i=0;i{
const node=nodesInShortestPathOrder[i];
document.getElementById(`node-${node.row}-${node.col}`)。className=
“节点最短路径”;
},50*i);
}
};
常量dijkstra=()=>{
const grid=nodeGrid.grid;
控制台日志(网格);
const startNode=grid[START_NODE_ROW][START_NODE_COL];
const finishNode=grid[FINISH_NODE_ROW][FINISH_NODE_COL];
const visitedNodesInoder=dijkstra(网格、开始节点、完成节点);
const nodesInShortestPathOrder=getNodesInShortestPathOrder(finishNode);
animateDijkstra(访问NodesNorder、NodesInshortstPathOrder);
};
//日志(nodeGrid.grid);
//log(dijkstra());
返回(
可视化Dijkstra算法
测试
{nodeGrid.grid.map((row,rowIdx)=>{
返回(
{row.map((node,nodeIdx)=>{
const{row,col,isStart,isFinish,isWall,isvisitored}=node;
返回(
);
})}
);
})}
);
};
导出默认路径查找可视化工具;
//----------------------------------------------------------
常量getInitialGrid=()=>{
常量网格=[];
for(让行=0;行<总行数;行++){
const currentRow=[];
for(设col=0;col{
返回{
上校,
一行
isStart:row===START\u NODE\u row&&col===START\u NODE\u col,
isFinish:row===FINISH\u NODE\u row&&col===FINISH\u NODE\u col,
距离:无限,
伊斯曼:错,
伊斯沃尔:错,
previousNode:空
};
};
const getNewGridWithWallToggled=(网格、行、列)=>{
const newGrid=grid.slice()
const handleMouseEnter = useCallback((row, col) => {
//console.log(mouseIsPressed);
if (mouseIsPressed.current) {
setNodeGrid(prevNodeGrid => ({
...prevNodeGrid,
grid: getNewGridWithWallToggled(prevNodeGrid.grid, row, col)
}));
}
}, []); <= empty dependency array
import _ from "lodash";
//--------
const visualizeDijkstra = () => {
const grid = _.cloneDeep(nodeGrid.grid);
// other code
}