ReactJS如何实现每秒一次循环?排序算法可视化步骤展示异常
问题分析与修复方案
你的代码存在几个核心问题导致无法看到排序过程:
- 直接修改State数组且未触发重渲染:你直接修改了
arr的元素(arr[i] = arr[minIndex]),但React的State必须通过setArr更新才能触发组件重渲染,否则页面不会同步变化。 - 错误的循环与useEffect使用:
useEffect不能放在while循环或条件语句中,违反React的Hook规则;同时arr.sort()会原地修改原数组,导致页面加载时数组就被直接排序,while (arr != arr.sort())的条件永远不成立(因为arr.sort()返回原数组引用),循环根本不会执行。 - SetTimeout闭包问题:for循环中直接使用
setTimeout会导致所有定时器共享同一个i变量,最终执行时i已经是循环的最后一个值,逻辑完全错误;且循环会一次性创建所有定时器,导致所有排序步骤几乎同时完成,看不到间隔效果。
修复后的代码
import React, { useState, useEffect } from 'react' const SortingAlgorithm: React.FC = () => { const [arr, setArr] = useState<number[]>([3, 1, 2, 5, 4]); useEffect(() => { // 复制原数组,避免修改state原始值 const array = [...arr]; let i = 0; const performSelectionSortStep = () => { if (i >= array.length - 1) return; // 排序完成,终止 let minIndex = i; // 找到当前未排序部分的最小值索引 for (let j = i + 1; j < array.length; j++) { if (array[j] < array[minIndex]) { minIndex = j; } } // 交换元素,生成新数组 const newArray = [...array]; [newArray[i], newArray[minIndex]] = [newArray[minIndex], newArray[i]]; setArr(newArray); i++; // 1秒后执行下一步 setTimeout(performSelectionSortStep, 1000); }; // 启动排序流程 const timer = setTimeout(performSelectionSortStep, 1000); // 组件卸载时清除定时器 return () => clearTimeout(timer); }, []); return ( <div style={{ display: 'flex', gap: '8px', alignItems: 'flex-end', height: '300px', padding: '20px' }}> {arr.map((value, index) => ( <div key={index} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}> <svg height="250" width="40"> <rect height={value * 50} width="35" y={250 - value * 50} fill="#4299e1" /> </svg> <span>{value}</span> </div> ))} </div> ) } export default SortingAlgorithm;
关键修改说明
- 用递归定时器控制步骤:通过
performSelectionSortStep函数递归调用,每次执行完一步排序后,1秒后触发下一步,确保每一步都有可见的间隔。 - Immutable更新State:每次排序步骤都生成新数组(
[...array]),通过setArr更新,触发组件重渲染,展示最新的数组状态。 - 避免原地修改数组:始终操作数组的副本,防止意外修改State原始值。
- 正确的useEffect使用:在组件挂载时启动排序流程,符合React Hook规则,且组件卸载时清除定时器,避免内存泄漏。
内容的提问来源于stack exchange,提问作者bascott
相关产品推荐
相关产品推荐

