javascript - 为什么 setTimeout 在我的冒泡排序函数中不起作用(REACT)
问题描述
我正在尝试可视化我的冒泡排序算法,所以我希望算法等待 50 毫秒才能可视化它。我尝试使用 setTimeout 和 async 函数,但它不起作用,当您删除 setTimeout 函数时,您可以看到数组排序,当它在函数中时不起作用。该项目已经安装了 bootstap@next 和 popper.js
import React, { useEffect, useState, Fragment } from 'react';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap.js';
import './App.css'
function App() {
const [values, setValues] = useState([43,4,3,56,6,3,36,56,7,5,45,34,87,99,34]);
const [render, setRender] = useState(false)
function forceRender() {
setRender(true)
}
useEffect(() => {
if(render) {
setRender(false)
}
}, [render])
function bubble(arr) {
for(let j = 0, len = arr.length; j < len; j++) {
for (let i = 0; i < len; i++) {
if (arr[i] > arr[i + 1]) {
setTimeout(()=>{
let temp = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = temp;
setValues(arr);
}, 50)
}
}
}
}
useEffect(() => {
bubble(values)
}, []);
useEffect(() => {
forceRender()
}, [values])
return (
<Fragment>
<nav className="navbar navbar-dark bg-dark">
<div className="container">
<span className="navbar-brand mb-0 h1">React Sorting</span>
</div>
</nav>
<div className="container sorting-container">
<div className="row">
<div className="sorting">
{
values.map(e => {
return (
<div className="bar" style={{height: `${e}%`}}>
<div className="bar-text">{e}</div>
</div>
)
})
}
</div>
</div>
</div>
</Fragment>
);
}
export default App;
解决方案
这段代码有很多问题阻止它工作。仅举几例:
forceRender()
功能不是必需的,也不起作用。useEffect
正在打破一些 React hooks 规则。该功能取决于两者bubble()
,并且values
- 任何具有像 ESLint 这样的 linter 的好的 IDE 都会指出这个问题并帮助指导您。作为一种快速的解决方法并且为简单起见,我刚刚移动了bubble()
内部,以及安装时初始数组的设置,以避免需要获取values
.for
循环bubble()
运行到完成,所有setTimeout
回调都指向同一个实例,arr
该实例已经运行到完成(这是经典 JS 面试问题的变体)。这就是为什么它从不重新渲染的原因——因为 in 中的值arr
已经运行到它们的最终状态并且没有改变。为了在不同时间点捕获数组的状态而不对原始代码进行重大更改,您可以在块范围内制作副本(请参见下面的代码)。setTimeout
毫秒都设置为同一时间,因此它们将同时运行。我怀疑您想查看逐个播放的进度,在这种情况下,您可以使时间成为循环j
中i
的函数-例如for
50 * i * j
- JSX map 函数中返回的元素应该有唯一的键。这是您应该在控制台中看到的运行时错误。
- 为了简单起见,我还减少了数组中的重复项,因此 React 更容易跟踪子元素的唯一键。
您可以运行的工作代码片段,以供参考:
const { useEffect, useState, Fragment } = React;
function App() {
const [values, setValues] = useState([]);
useEffect(() => {
function bubble(arr) {
// Note: this loop runs to completion before any setTimeout callbacks are run.
for (let j = 0, len = arr.length - 1; j < len; j++) {
for (let i = 0; i < len; i++) {
if (arr[i] > arr[i + 1]) {
// Make a copy so the setTimeout below has a "snapshot" of the array at
// this point in time.
const arrCopy = [...arr];
let temp = arrCopy[i + 1];
arrCopy[i + 1] = arrCopy[i];
arrCopy[i] = temp;
arr = arrCopy;
setTimeout(() => {
setValues(arrCopy);
}, 100 * i * j);
}
}
}
}
bubble([43, 4, 3, 56, 6, 36, 7, 5, 45, 34, 87, 99]);
}, []);
return (
<Fragment>
<nav className="navbar navbar-dark bg-dark">
<div className="container">
<span className="navbar-brand mb-0 h1"> React Sorting </span>
</div>
</nav>
<div className="container sorting-container">
<div className="row">
<div className="sorting">
{values.map((val) => {
return (
<div key={val} className="bar">
<div className="bar-text"> {val} </div>
</div>
);
})}
</div>
</div>
</div>
</Fragment>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<body>
<div id="root" />
</body>
推荐阅读
- asp.net-core-webapi - EF Core FromSQLRaw 没有调用数据库?
- php - 自定义帖子类型未显示在管理栏中
- spring-batch - 如何在 Spring Batch 项目中为 ItemProcessor 实现逻辑
- ios - Swift - 每 50 次后使用睡眠者运行 1000 个异步任务 - 如何通信 btw DispatchGroups
- git - Git:如何将开发重置为大师?
- python - Python:如何解决为预测未来帧序列而开发的变分自动编码器卷积模型的低精度问题?
- python - Pandas-连接两列字符串列表
- javascript - 将 SVG 导出到 PNG 截断的画布
- javascript - 使用 JavaScript 读入脚本标签的值
- python - 如何正确创建新文件并对其应用多行输入?