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

排序算法可视化工具无法实现洗牌功能:setTimeout更新不渲染

问题分析与修复方案

核心问题

你的代码存在三个关键问题,导致洗牌动画异常:

1. swapBars 函数的逻辑错误与不可变性问题

  • 直接引用原数组 const _bars = bars,修改的是原数组而非副本,违反React状态不可变原则
  • 交换对象时仅修改了变量引用,并未实际交换数组中元素的位置
  • 直接修改bar对象的left属性,未创建新对象,React无法检测到状态变化触发重渲染

2. shuffleBars 的闭包陷阱

循环中的currentIndex和randomIndex是共享变量,当setTimeout触发时,循环已执行完毕,所有定时器都会使用最后一次循环的索引值,导致重复操作同一组元素

3. 状态更新未基于最新状态的链式处理

批量触发的setTimeout会同时读取旧状态,导致状态更新冲突,无法按顺序完成洗牌步骤


修复后的完整代码

1. 修复 swapBars 函数

// 正确实现不可变的元素交换,返回新数组与新对象
const swapBars = (bars, idx1, idx2) => {
  if (!bars || idx1 < 0 || idx2 < 0 || idx1 >= bars.length || idx2 >= bars.length) {
    return bars;
  }
  // 创建数组副本
  const newBars = [...bars];
  // 创建两个bar的副本,避免修改原对象
  const bar1 = {...newBars[idx1]};
  const bar2 = {...newBars[idx2]};
  
  // 交换left属性
  const tempLeft = bar1.left;
  bar1.left = bar2.left;
  bar2.left = tempLeft;
  
  // 交换数组中的位置
  newBars[idx1] = bar2;
  newBars[idx2] = bar1;
  
  return newBars;
};

2. 修复 shuffleBars 函数

使用递归实现逐步洗牌,确保每一步都基于最新状态,同时避免闭包陷阱:

const shuffleBars = (bars) => {
  const shuffleStep = (currentIndex) => {
    if (currentIndex <= 0) return;
    
    const randomIndex = Math.floor(Math.random() * currentIndex);
    setTimeout(() => {
      setBarsToRender(prev => swapBars(prev, currentIndex, randomIndex));
      // 执行下一步洗牌
      shuffleStep(currentIndex - 1);
    }, 50);
  };
  
  shuffleStep(bars.length - 1);
};

3. 同步洗牌函数 initBars 适配新逻辑

const initBars = (bars) => {
  let currentIndex = bars.length - 1;
  let shuffledBars = [...bars];
  while (currentIndex > 0) {
    const randomIndex = Math.floor(Math.random() * currentIndex);
    shuffledBars = swapBars(shuffledBars, currentIndex, randomIndex);
    currentIndex--;
  }
  setBarsToRender(shuffledBars);
};

改动说明

  • 不可变性处理:所有状态修改都创建数组和对象的副本,确保React能检测到变化并正确重渲染
  • 闭包陷阱解决:用递归代替循环+setTimeout,每一步的索引值都被正确绑定,不会出现共享变量问题
  • 顺序执行:递归调用确保上一步洗牌完成后再执行下一步,动画按顺序逐步展示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:17