Reactjs 在 for 循环结束之前不会渲染

重要的!这不是异步 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.");

    };

明月笑刀无情
浏览 123回答 3
3回答

神不在的星期二

React 将尽可能关注性能。因此,例如,它将聚合一堆 setState 调用并批量处理它们,以防止不必要的渲染。非常适合大多数 Web 应用程序,但不适用于这样的可视化。您可以做的是等待渲染完成,然后再进入下一个状态。计时器和 async/await 将使这很容易阅读和完成。// Returns a promise that resolves after given delayconst timer = (delay) => {&nbsp; &nbsp; return new Promise((resolve) => setTimeout(resolve, delay));}const bubbleSort = async(delay) => {&nbsp; &nbsp; let temp,&nbsp; &nbsp; &nbsp; &nbsp; array = Object.assign([], getArray),&nbsp; &nbsp; &nbsp; &nbsp; classes = Object.assign([], getClasses);&nbsp; &nbsp; for (let i = array.length; i > 0; i--) {&nbsp; &nbsp; &nbsp; &nbsp; for (let j = 0; j < i - 1; j++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classes[j] = "array-bar compared-bar";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classes[j + 1] = "array-bar compared-bar";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (array[j] > array[j + 1]) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; temp = array[j];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array[j] = array[j + 1];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array[j + 1] = temp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //console.log((array.length - i) * 200 + (j + 1));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setArray(array);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setClasses(classes);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Wait delay amount in ms before continuing, give browser time to render last update&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; await timer(delay);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; console.log("done.");};更新需要更改的下一部分代码是如何修改数组。当你调用 时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 contentssetArray([...array]);

慕慕森

当组件的状态发生变化时,setState 总是会触发重新渲染。在挂钩的情况下,将状态更新为与前一个值相同的值不会导致重新渲染。因此,在您的情况下,显示更改重新渲染是必要的。这是您正在寻找的工作演示。https://stackblitz.com/edit/react-qaawgg?file=index.jsimport React, { Component } from 'react';import { render } from 'react-dom';class App extends Component {&nbsp; constructor() {&nbsp; &nbsp; super();&nbsp; &nbsp; this.state = {&nbsp; &nbsp; &nbsp; arr: [],&nbsp; &nbsp; &nbsp; clsarr:[]&nbsp; &nbsp; };&nbsp; }timeDelay = (delay) => {&nbsp; &nbsp; return new Promise((resolve) => setTimeout(resolve, delay));}&nbsp; &nbsp; &nbsp;resetArray = (size)=> {&nbsp; &nbsp; &nbsp; &nbsp; const array = [];&nbsp; &nbsp; &nbsp; &nbsp; const classesArray = [];&nbsp; &nbsp; &nbsp; &nbsp; for (let i = 0; i < size; i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array.push(this.randomInt(20, 800));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classesArray.push("array-bar");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; this.setState({arr:array,clsarr:classesArray});&nbsp; &nbsp; };&nbsp; &nbsp; bubbleSort = async(delay) => {&nbsp; &nbsp; &nbsp; &nbsp; let temp,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array = Object.assign([], this.state.arr),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classes = Object.assign([], this.state.clsarr);&nbsp; &nbsp; &nbsp; &nbsp; for (let i = array.length; i > 0; i--) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (let j = 0; j < i - 1; j++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classes[j] = "array-bar compared-bar";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; classes[j + 1] = "array-bar compared-bar";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (array[j] > array[j + 1]) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; temp = array[j];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array[j] = array[j + 1];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array[j + 1] = temp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //console.log((array.length - i) * 200 + (j + 1));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.setState({arr:array,clsarr:classes})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;await this.timeDelay(500);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; console.log("done.");&nbsp; &nbsp; };&nbsp; &nbsp; randomInt(min, max) {&nbsp; &nbsp; return Math.floor(Math.random() * (max - min + 1)) + min;}&nbsp; render() {&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; <div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <div className="menu">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <button onClick={() => this.resetArray(50)}>Geneate new array</button>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <button onClick={()=>this.bubbleSort()}>Do bubble sort</button>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <div className="array-container">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {this.state.arr.map((value, i) => (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <div&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; className={this.state.clsarr[i]}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; key={i}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; >{value}<br/></div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ))}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div></div>&nbsp; &nbsp; );&nbsp; }}render(<App />, document.getElementById('root'));

缥缈止盈

也许获取是异步的,但是一旦进入循环,它就会变成同步的,64 位每秒运行高达 18,446,744,073,709,551,615 (264 - 1) 条指令,而不是人眼和屏幕能够看到的。是的,我查看了维基百科以找出数字。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript