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

算法可视化:异步动画运行时如何实时应用更新的animationSpeed参数?

问题解决:算法可视化动画运行时修改速度不生效

问题描述

开发算法可视化工具时,通过animationSpeed、running参数控制冒泡排序动画,但动画运行中修改animationSpeed的新值无法在异步的animateBubbleSort函数中生效。

问题根源

组件每次因animationSpeed或running变化重新渲染时,都会执行let sortingObj = new SortingAlgorithm(running, animationSpeed)创建新的实例。此时正在运行动画的是旧实例,而调速按钮更新的是新创建实例的animationSpeed,旧实例的速度未被修改,导致动画无响应。

解决方案

1. 使用useRef保存SortingAlgorithm实例

useRef创建的引用在组件整个生命周期内保持不变,避免每次渲染重建实例,确保动画运行时始终操作同一个实例。

2. 调整实例初始化与状态同步逻辑

  • 在组件挂载时初始化实例,卸载时停止动画避免内存泄漏。
  • 调速时直接更新已有实例的animationSpeed,确保正在运行的动画能读取到新值。
  • 排序时传递数组副本,避免直接修改React state中的数组。

修改后的代码

AlgorithmVisualization组件

import { useState, useEffect, useRef } from 'react';

const AlgorithmVisualization = () => {
  const [animationSpeed, setAnimationSpeed] = useState(1000);
  const [array, setArray] = useState([]);
  const [running, setRunning] = useState(false);
  
  // 用useRef保存SortingAlgorithm实例,确保全局唯一
  const sortingObjRef = useRef(null);

  // 组件挂载时初始化实例,卸载时停止动画
  useEffect(() => {
    sortingObjRef.current = new SortingAlgorithm(running, animationSpeed);
    return () => {
      if (sortingObjRef.current) {
        sortingObjRef.current.stopAnimation();
      }
    };
  }, []);

  const handleBubbleSort = () => {
    setRunning(true);
    // 重置实例的running状态为true
    sortingObjRef.current.running = true;
    // 传递数组副本,避免修改原state数组
    sortingObjRef.current.animateBubbleSort([...array]);
  };

  const handleStopButton = () => {
    setRunning(false);
    sortingObjRef.current.stopAnimation();
  };

  const handleIncreaseButton = () => {
    const newSpeed = Math.max(100, animationSpeed - 100);
    setAnimationSpeed(newSpeed);
    sortingObjRef.current.updateAnimationSpeed(newSpeed);
  };

  const handleDecreaseButton = () => {
    const newSpeed = Math.min(2000, animationSpeed + 100);
    setAnimationSpeed(newSpeed);
    sortingObjRef.current.updateAnimationSpeed(newSpeed);
  };

  return (
    <div>
      <div className="array-container">
        {array.map((value, idx) => (
          <div
            className="array-bar"
            key={idx}
            style={{ height: `${value}%` }}
          ></div>
        ))}
      </div>
      <button onClick={handleDecreaseButton}>Decrease Animation Speed</button>
      <button onClick={handleStopButton}>Stop</button>
      <button onClick={handleIncreaseButton}>Increase Animation Speed</button>
      <br></br>
      <button onClick={handleBubbleSort}>Bubble Sort</button>
    </div>
  );
};

SortingAlgorithm类(核心逻辑无需修改,确保读取实时的this.animationSpeed)

class SortingAlgorithm{
  constructor(running, animationSpeed){
    this.animationSpeed = animationSpeed;
    this.running = running;
  }

  stopAnimation(){
    this.running = false;
  }

  updateAnimationSpeed(newSpeed){
    this.animationSpeed = newSpeed;
  }
  
  async animateBubbleSort(array){
    const arrayBars = document.getElementsByClassName('array-bar');
    const n = array.length;
  
    for (let i = 0; i < n - 1; i++) {
      for (let j = 0; j < n - i - 1; j++) {        
        if(!this.running){
            break;
        }

        const [idx1, idx2] = [j, j+1];
        const bar1Style = arrayBars[idx1].style;
        const bar2Style = arrayBars[idx2].style;
  
        let isSwap = false;         
  
        if (array[j] > array[j + 1]) {
          isSwap = true;
          const temp = array[j];
          array[j] = array[j + 1];
          array[j + 1] = temp;
        }
  
        bar1Style.backgroundColor = SECONDELEMENTCOLOR;
        bar2Style.backgroundColor = FIRSTELEMENTCOLOR;
  
        // 每次await都读取当前实例的animationSpeed,确保新值生效
        await delay(this.animationSpeed);      
  
        if (isSwap) {
          const tempHeight = bar1Style.height;
          bar1Style.height = bar2Style.height;
          bar2Style.height = tempHeight;
  
          bar1Style.backgroundColor = FIRSTELEMENTCOLOR;
          bar2Style.backgroundColor = SECONDELEMENTCOLOR;
        }
  
        await delay(this.animationSpeed);
        
        bar1Style.backgroundColor = NOCOLOR;
        bar2Style.backgroundColor = NOCOLOR;
      }
      
      if(!this.running){
        break;
      }
  
      const lastBarStyle = arrayBars[n - 1 - i].style;
      lastBarStyle.backgroundColor = SORTEDCOLOR;
    }

    if(!this.running){
      return;
    }
  
    const firstBarStyle = arrayBars[0].style;
    firstBarStyle.backgroundColor = SORTEDCOLOR;
  }
}

注:确保delay函数是一个返回Promise的延迟函数,例如:

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

内容的提问来源于stack exchange,提问作者Navkar Jain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:35:55