lav*_*iRZ 4 javascript reactjs
重要的!这不是异步 API 的问题!我尝试创建一个冒泡排序可视化器,当我运行算法本身时,我希望用户实际看到它的运行情况。所以每次我进行交换时,我都希望用户能够看到它发生。当bubbleSort运行内部的循环并更新状态Classes和 时Array,没有任何反应,直到循环完全结束。如果我将 abreak;放入循环中,则在循环停止时反应渲染。问题是什么?我该如何解决?
编辑:
如果你有答案,请解释它为什么起作用,以及我应该如何在我的代码中实现它。
import React, { useState, useEffect } from "react";
import "./SortingVisualizer.css";
import { render } from "@testing-library/react";
const SortingVisualizer = () => {
const [getArray, setArray] = useState([]);
const [getClasses, setClasses] = useState([""]);
useEffect(() => {
resetArray(200);
}, []);
useEffect(() => {}, [getArray, getClasses]);
const resetArray = size => {
const array = [];
const classesArray = [];
for (let i = 0; i < size; i++) {
array.push(randomInt(20, 800));
classesArray.push("array-bar");
}
setArray(array);
setClasses(classesArray);
};
const bubbleSort = delay => {
let temp,
array = Object.assign([], getArray),
classes = Object.assign([], getClasses);
for (let i = array.length; i > 0; i--) {
for (let j = 0; j < i - 1; j++) {
classes[j] = "array-bar compared-bar";
classes[j + 1] = "array-bar compared-bar";
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
//console.log((array.length - i) * 200 + (j + 1));
setArray(array);
setClasses(classes);
break;
}
}
console.log("done.");
};
return (
<>
<div className="menu">
<button onClick={() => resetArray(200)}>Geneate new array</button>
<button onClick={bubbleSort}>Do bubble sort</button>
</div>
<div className="array-container">
{getArray.map((value, i) => (
<div
className={getClasses[i]}
key={i}
style={{ height: `${value * 0.1}vh` }}
></div>
))}
</div>
</>
);
};
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export default SortingVisualizer;
Run Code Online (Sandbox Code Playgroud)
React 会尽可能地专注于性能。例如,它会聚合一堆 setState 调用并分批处理它们以防止不必要的渲染。适用于大多数 Web 应用程序,不适用于此类可视化。
您可以做的是等待渲染完成,然后再进入下一个状态。计时器和 async/await 将使这很容易阅读和完成。
// Returns a promise that resolves after given delay
const timer = (delay) => {
return new Promise((resolve) => setTimeout(resolve, delay));
}
const bubbleSort = async(delay) => {
let temp,
array = Object.assign([], getArray),
classes = Object.assign([], getClasses);
for (let i = array.length; i > 0; i--) {
for (let j = 0; j < i - 1; j++) {
classes[j] = "array-bar compared-bar";
classes[j + 1] = "array-bar compared-bar";
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
//console.log((array.length - i) * 200 + (j + 1));
setArray(array);
setClasses(classes);
// Wait delay amount in ms before continuing, give browser time to render last update
await timer(delay);
}
}
console.log("done.");
};
Run Code Online (Sandbox Code Playgroud)
更新
需要更改的下一部分代码是如何修改数组。当您调用 时setArray,React 会查看您传入的值并进行浅层比较以查看它是否与现有值不同。如果它们相同,它会忽略它并且不会重新渲染。对于像 String、Boolean 和 Number 这样的原始数据类型,这不是问题。对于像对象、数组和函数这样的复杂数据类型,这是一个问题,因为它比较的是内存地址,而不是内容。
您的代码正在修改相同的数组,然后将其传递给setArray,后者会看到它已经拥有的相同内存地址并忽略更新。
那么为什么它仍然更新前两个呢?实际上我不太确定。可能点击甚至告诉 React 它应该重新渲染。
以下是解决此问题的方法。确保setArray每次都提供一个新的内存地址,以便触发重新渲染。您的另一个选择是使用强制渲染技术。
// Create a new array and spread the old arrays contents out inside of it.
// New memory address, same contents
setArray([...array]);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
201 次 |
| 最近记录: |