You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React冒泡排序可视化时DOM高度未随排序过程动态更新问题

问题核心原因
  • JS是单线程运行,你写的同步while+for排序循环会直接占满主线程,期间浏览器没有空闲执行DOM重绘,所有DOM修改都会被攒到整个循环跑完才一次性执行,自然看不到中间过程。
  • 你直接修改state引用的原数组(arraY[i] = smaller)属于直接变更状态,React检测不到状态变化,不会触发重渲染;就算你在循环里连续调用setArray,同步执行的setState会被React批量合并,最终只会渲染最后一次的结果。
  • 之前试setTimeout没效果,本质是没有把每一步排序操作拆成异步任务按间隔依次执行,要么是给整个排序套了一层延迟,要么是循环里setTimeout的延迟时间没有按步长递增,所有回调几乎同时触发,还是看不到逐帧变化。
修复方案
  • 删掉手动操作ref改DOM的逻辑,React下视图完全由state驱动,数组每变一次就setArray传新的数组拷贝,让React自动重渲染柱状条高度,手动改DOM很容易和虚拟DOM更新冲突。
  • 把同步阻塞的排序逻辑改成异步执行,每完成一次元素交换,就等待一小段时间(比如10ms)再执行下一轮比较,给浏览器留出重绘DOM的空闲时间。
  • 排序开始前先拷贝一份原数组做排序操作,不要直接改state里存的原数组引用,避免状态变更检测失效。
修正后可运行代码
import { useState, useEffect } from 'react';
import './App.css';

function App() {
  const [array, setArray] = useState([]);
  // 封装延迟函数,控制动画间隔
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

  // 初始化随机数组
  useEffect(()=> {
    const startArray = [];
    for(let i=0; i < 51; i++){
      // 直接+1避免生成0值,省掉额外判断
      let randomNumber = Math.floor(Math.random() * 27) + 1;
      startArray.push(randomNumber)
    }
    setArray(startArray)
  }, [])

  // 异步冒泡排序
  const bubbleSort = async (arr) => {
    // 拷贝原数组,不直接修改state引用
    const sortArr = [...arr];
    const len = sortArr.length;
    for (let i = 0; i < len - 1; i++) {
      for (let j = 0; j < len - 1 - i; j++) {
        if (sortArr[j] > sortArr[j+1]) {
          // 交换相邻元素
          [sortArr[j], sortArr[j+1]] = [sortArr[j+1], sortArr[j]];
          // 传入新数组拷贝触发重渲染
          setArray([...sortArr]);
          // 让出主线程,等待浏览器重绘
          await sleep(10);
        }
      }
    }
  }

  const handleSort = ()=> {
    bubbleSort(array);
  }

  return (
    <div className="App">
      <nav>
        <h1 onClick={handleSort}>BUBBLE SORT</h1>
        <h1 onClick={handleSort}>--- SORT</h1>
        <h1 onClick={handleSort}>--- SORT</h1>
        <h1 onClick={handleSort}>--- SORT</h1>
      </nav>
      <div className='container'>
        {array.map((item, idx)=>{
          // 直接由state驱动样式,无需手动操作DOM
          return <div key={idx} style={{height: `${item*2}vh`}} className="bar"></div>
        })
        }
      </div>
    </div>
  );
}

export default App;
补充说明
  • 渲染柱状条的时候记得加key属性,数组固定长度的场景用索引当key就可以,避免React节点复用出错。
  • 调整sleep函数的入参毫秒值就能改动画速度,数值越小排序动画越快。
  • 其他排序算法的可视化逻辑完全通用:每一步数组变动都生成新拷贝更新state,加短延迟让出主线程给浏览器重绘即可。

内容的提问来源于stack exchange,提问作者Coder apprentice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 01:27:18