为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

明月笑刀无情 2022-05-26 11:27:28
重要的!这不是异步 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.");    };
查看完整描述

3 回答

?
神不在的星期二

TA贡献1963条经验 获得超6个赞

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.");

};

更新


需要更改的下一部分代码是如何修改数组。当你调用 时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]);


查看完整回答
反对 回复 2022-05-26
?
慕慕森

TA贡献1856条经验 获得超17个赞

当组件的状态发生变化时,setState 总是会触发重新渲染。在挂钩的情况下,将状态更新为与前一个值相同的值不会导致重新渲染。因此,在您的情况下,显示更改重新渲染是必要的。这是您正在寻找的工作演示。


https://stackblitz.com/edit/react-qaawgg?file=index.js


import React, { Component } from 'react';

import { render } from 'react-dom';


class App extends Component {

  constructor() {

    super();

    this.state = {

      arr: [],

      clsarr:[]

    };

  }

timeDelay = (delay) => {

    return new Promise((resolve) => setTimeout(resolve, delay));

}


     resetArray = (size)=> {

        const array = [];

        const classesArray = [];

        for (let i = 0; i < size; i++) {

            array.push(this.randomInt(20, 800));

            classesArray.push("array-bar");

        }

        this.setState({arr:array,clsarr:classesArray});

    };


    bubbleSort = async(delay) => {

        let temp,

            array = Object.assign([], this.state.arr),

            classes = Object.assign([], this.state.clsarr);

        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));


                this.setState({arr:array,clsarr:classes})

                 await this.timeDelay(500);


            }

        }

        console.log("done.");

    };


    randomInt(min, max) {

    return Math.floor(Math.random() * (max - min + 1)) + min;

}


  render() {

    return (

      <div>

            <div className="menu">

                <button onClick={() => this.resetArray(50)}>Geneate new array</button>

                <button onClick={()=>this.bubbleSort()}>Do bubble sort</button>

            </div>

            <div className="array-container">

                {this.state.arr.map((value, i) => (

                    <div

                        className={this.state.clsarr[i]}

                        key={i}

                    >{value}<br/></div>

                ))}

            </div></div>

    );

  }

}


render(<App />, document.getElementById('root'));



查看完整回答
反对 回复 2022-05-26
?
缥缈止盈

TA贡献2041条经验 获得超4个赞

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



查看完整回答
反对 回复 2022-05-26
  • 3 回答
  • 0 关注
  • 122 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信