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

如何用useEffect实现排序迭代延迟展示?React排序可视化问题

排序算法可视化React应用的延迟问题解决

问题描述

我正在实现排序算法并构建React应用,用于展示未排序数组在每轮迭代中的变化。为了让变化可见,应用需要在每次迭代后暂停一段时间,我尝试使用setTimeout函数和useEffect Hook实现,但未生效。

组件代码

import { useEffect, useState } from "react"
import { SortAlgorithms } from "../Utils/Sort"


export default function SortingBoard(){
    const [board, setBoard] = useState([10,9,8,7,6,5,4,3,2,1])
    const [delay, setDelay] = useState(500)
    const [algorithm, setAlgorithm] = useState(() => SortAlgorithms[0])
    const [isIterating, setIsIterating] = useState(false)

    useEffect(() => {
        async function sleep(){
            const timer = new Promise(r => setTimeout(r, delay));
            await timer
        }

        sleep()
    }, [board])

    const handleSort = async () => {
        setIsIterating(true)
        algorithm({board, setBoard})
        setIsIterating(false)
    }

    return (
        <div className="bord-layout">
            <div className="bord">
                {board.map( (item, idx) =>{
                    return <h1 key={idx}>{item}</h1>
                })}
            </div>

            <div className="bord-options">
                <select name="algorithms" onChange={e => setAlgorithm(() => SortAlgorithms[e.target.value])}>
                    <option value={0}>Bubble Sort</option>
                    <option value={1}>Sellection Sort</option>
                </select>
                <button disabled={isIterating} onClick={handleSort}>
                    Sort
                </button>
            </div>
        </div>
    )
}

排序函数代码

function BubbleSort({board, setBoard}){
    for(let i = 0; i < board.length; i++){
        for(let j = 0; j < board.length - 1; j++){
            if(board[j] > board[j + 1]){
                const temp = board[j]

                board[j] = board[j + 1]
                board[j + 1] = temp
                setBoard([...board])
            }
        }
    }
}

function SelectionSort({board, setBoard}){
    for(let i = 0; i < board.length; i++){
        let min = i
        for(let j = i + 1; j < board.length; j++){
            if( board[j] < board[min]){
                min = j
            }
        }
        const temp = board[i]
        board[i] = board[min]
        board[min] = temp
        setBoard([...board])
    }
}

export const SortAlgorithms = [BubbleSort, SelectionSort]

具体问题是:每次迭代都会调用setTimeout,但不会等待其完成。请问我是否应该使用useEffect和setTimeout,还是有其他可行方案?


问题根源

  1. 同步循环导致批量更新:排序函数是同步for循环,会瞬间执行完所有交换逻辑并调用setBoard,React会批量处理这些状态更新,最终只渲染最后一次结果,中间步骤完全看不到。
  2. useEffect的sleep无效:useEffect里的sleep只是在board变化后等待,但排序过程是同步完成的,等sleep执行时所有迭代已经结束。
  3. handleSort未等待排序完成:algorithm是同步函数,调用后立刻执行setIsIterating(false),导致按钮提前解禁。

解决方案:异步排序函数+等待执行

不需要依赖useEffect做延迟,直接把排序函数改成异步,在每次迭代(或交换)后加入延迟,同时让handleSort等待排序完成。

修改后的排序函数代码

async function BubbleSort({ board, setBoard, delay }) {
    // 复制原数组,避免直接修改状态数组
    let currentBoard = [...board];
    for (let i = 0; i < currentBoard.length; i++) {
        for (let j = 0; j < currentBoard.length - 1 - i; j++) {
            if (currentBoard[j] > currentBoard[j + 1]) {
                // 交换元素
                [currentBoard[j], currentBoard[j + 1]] = [currentBoard[j + 1], currentBoard[j]];
                // 更新状态
                setBoard([...currentBoard]);
                // 等待延迟
                await new Promise(resolve => setTimeout(resolve, delay));
            }
        }
    }
}

async function SelectionSort({ board, setBoard, delay }) {
    let currentBoard = [...board];
    for (let i = 0; i < currentBoard.length; i++) {
        let min = i;
        for (let j = i + 1; j < currentBoard.length; j++) {
            if (currentBoard[j] < currentBoard[min]) {
                min = j;
            }
        }
        // 交换元素
        [currentBoard[i], currentBoard[min]] = [currentBoard[min], currentBoard[i]];
        setBoard([...currentBoard]);
        // 等待延迟
        await new Promise(resolve => setTimeout(resolve, delay));
    }
}

export const SortAlgorithms = [BubbleSort, SelectionSort];

修改后的组件代码

import { useState } from "react"
import { SortAlgorithms } from "../Utils/Sort"


export default function SortingBoard(){
    const [board, setBoard] = useState([10,9,8,7,6,5,4,3,2,1])
    const [delay, setDelay] = useState(500)
    const [algorithm, setAlgorithm] = useState(SortAlgorithms[0])
    const [isIterating, setIsIterating] = useState(false)

    const handleSort = async () => {
        setIsIterating(true)
        // 传入delay参数,等待排序完成
        await algorithm({ board, setBoard, delay })
        setIsIterating(false)
    }

    return (
        <div className="bord-layout">
            <div className="bord">
                {board.map( (item, idx) => (
                    <h1 key={idx}>{item}</h1>
                ))}
            </div>

            <div className="bord-options">
                <select 
                    name="algorithms" 
                    onChange={e => setAlgorithm(SortAlgorithms[e.target.value])}
                >
                    <option value={0}>Bubble Sort</option>
                    <option value={1}>Selection Sort</option>
                </select>
                <button disabled={isIterating} onClick={handleSort}>
                    Sort
                </button>
            </div>
        </div>
    )
}

关键改动说明

  • 排序函数异步化:给排序函数加上async关键字,在每次状态更新后用await setTimeout实现延迟,让React有时间渲染中间状态。
  • 传递delay参数:把组件中的delay状态传给排序函数,控制每步的等待时间。
  • 复制状态数组:不直接修改原board数组,而是创建副本currentBoard,避免状态突变导致的不可预测问题。
  • 等待排序完成:在handleSort中用await调用排序函数,确保排序结束后再解禁按钮。
  • 移除无用的useEffect:原来的useEffect对延迟没有帮助,直接删除即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 17:34:55