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

路径寻路应用递归函数条件终止失效问题求助

问题分析

你的递归停止逻辑失效主要有两个核心原因:

  1. React useState的闭包陷阱:stopVisiting是组件状态,startVisiting函数在每次调用时都会捕获当前的stopVisiting值。当你调用setStopVisiting(true)后,已经处于调用栈或setTimeout队列中的startVisiting实例,拿到的还是更新前的false值,不会立即停止。
  2. setTimeout的任务队列特性:一旦setTimeout把递归调用排进任务队列,即使后续stopVisiting变为true,这些已经排队的调用还是会执行,除非在执行前再次检查停止条件。

另外代码里还有两个小问题:

  • 网格是30行(i从0到29),但判断visElement.i < 39明显错误,应该改为visElement.i < 29;
  • setGrid是异步更新,setTimeout里直接用grid获取邻居,拿到的可能是旧的网格状态。
解决方案

改用useRef来存储停止标记(因为ref的current属性是可变的,所有函数都能拿到最新值),同时在每次递归调用前检查停止状态,修复网格引用问题:

import { useState, useRef } from 'react';

// ... 其他组件代码

const stopVisitingRef = useRef(false);
const [grid, setGrid] = useState(/* 你的初始网格 */);

const startVisiting = (visElement) => {
  // 先检查停止标记,直接终止
  if (stopVisitingRef.current) {
    console.log("Stop the function here");
    return;
  }

  // 到达终点,设置停止标记
  if (visElement.i === endElement.i && visElement.j === endElement.j) {
    stopVisitingRef.current = true;
    return;
  }

  // 遇到障碍,直接返回
  if (visElement.wall) return;

  // 已访问过,直接返回
  if (visElement.visited) return;

  // 更新网格标记为已访问
  const newGrid = [...grid];
  newGrid[visElement.i][visElement.j].visited = true;
  setGrid(newGrid);

  // 用更新后的newGrid获取邻居,避免旧引用问题
  setTimeout(() => {
    // 每次递归前再次检查停止标记
    if (!stopVisitingRef.current && visElement.i > 0) {
      startVisiting(newGrid[visElement.i - 1][visElement.j]);
    }
    if (!stopVisitingRef.current && visElement.i < 29) {
      startVisiting(newGrid[visElement.i + 1][visElement.j]);
    }
    if (!stopVisitingRef.current && visElement.j > 0) {
      startVisiting(newGrid[visElement.i][visElement.j - 1]);
    }
    if (!stopVisitingRef.current && visElement.j < 59) {
      startVisiting(newGrid[visElement.i][visElement.j + 1]);
    }
  }, 500);
};
关键修改点
  • 用useRef(false)替代useState(false):stopVisitingRef.current可以被直接修改,所有startVisiting实例都能拿到最新值,避免闭包陷阱;
  • 将停止检查放在函数最开头:只要标记为true,直接终止当前调用;
  • 在setTimeout的每个递归调用前都检查停止标记:阻止已经排队的不必要调用执行;
  • 用newGrid获取邻居元素:确保拿到的是最新的已更新网格状态;
  • 修复了行号判断的错误:30行网格的最大行索引是29。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 06:52:49