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

如何基于页面索引标记问卷问题完成状态?代码异常求助

问题描述

我有一个包含11个问题的表单,需要构建进度条来更新每个问题对应的对象数组,标记其完成/未完成状态:

  • 仅点击「下一步」时标记当前页面问题为完成
  • 点击「上一步」时标记当前页面问题为未完成

示例流程:

  • 处于问题1(索引0)时状态为未完成,进入问题2(索引1)后问题1变为完成
  • 处于问题3(索引2)时状态为未完成,返回问题2(索引1)后问题2变为未完成

当前代码逻辑大致可行,但存在异常:连续点击两次「下一步」后点击「上一步」,需点击两次「上一步」才能正确更新状态。

代码如下:

const [currentPage, setCurrentPage] = useState(0);

const [progress, setProgress] = useState([
    { pageIndex: 0, completed: false },
    { pageIndex: 1, completed: false },
    { pageIndex: 2, completed: false },
    { pageIndex: 3, completed: false },
    { pageIndex: 4, completed: false },
    { pageIndex: 5, completed: false },
    { pageIndex: 6, completed: false },
    { pageIndex: 7, completed: false },
    { pageIndex: 8, completed: false },
    { pageIndex: 9, completed: false },
    { pageIndex: 10, completed: false },
]);

const handleNavButtonNext = () => {
    // Mark previous page as complete
    const newProgress = [...progress];
    newProgress[currentPage].completed = true;
    setProgress(newProgress);

    // Move to next page
    setCurrentPage(currentPage + 1);

};
const handleNavButtonBack = () => {
    // Mark current page as incomplete
    const newProgress = [...progress];
    newProgress[currentPage].completed = false;
    setProgress(newProgress);

    // Move to previous page
    setCurrentPage(currentPage - 1);

};
问题原因

核心问题在于React的useState状态更新是异步且批量处理的,当你连续点击按钮时,事件处理函数中捕获到的currentPage和progress都是更新前的旧值,导致状态更新逻辑出错:

  1. 连续点击两次「下一步」时,第二次点击触发handleNavButtonNext时,currentPage还没完成第一次的更新(依然是初始的旧值),所以两次操作都标记了同一个页面索引为完成,而不是依次标记前一页并跳转。
  2. 后续点击「上一步」时,需要多次点击才能抵消之前错误的状态更新,最终让进度状态回到正确逻辑。
修复方案

使用函数式更新来获取最新的状态值,确保每次状态更新都基于当前最新的状态,而不是捕获到的旧值。修改后的代码如下:

const [currentPage, setCurrentPage] = useState(0);

const [progress, setProgress] = useState([
    { pageIndex: 0, completed: false },
    { pageIndex: 1, completed: false },
    { pageIndex: 2, completed: false },
    { pageIndex: 3, completed: false },
    { pageIndex: 4, completed: false },
    { pageIndex: 5, completed: false },
    { pageIndex: 6, completed: false },
    { pageIndex: 7, completed: false },
    { pageIndex: 8, completed: false },
    { pageIndex: 9, completed: false },
    { pageIndex: 10, completed: false },
]);

const handleNavButtonNext = () => {
    setCurrentPage(prevPage => {
        // 基于最新的旧页面索引,标记为完成
        setProgress(prevProgress => {
            const newProgress = [...prevProgress];
            newProgress[prevPage].completed = true;
            return newProgress;
        });
        return prevPage + 1;
    });
};

const handleNavButtonBack = () => {
    setCurrentPage(prevPage => {
        // 基于最新的当前页面索引,标记为未完成
        setProgress(prevProgress => {
            const newProgress = [...prevProgress];
            newProgress[prevPage].completed = false;
            return newProgress;
        });
        return prevPage - 1;
    });
};

逻辑说明

  • 在更新currentPage时,使用回调函数prevPage => ...获取最新的页面索引,确保每次跳转都是基于当前最新的页面位置。
  • 同时在回调内部更新progress,使用prevProgress获取最新的进度数组,确保标记的是正确的页面索引(跳转前的页面)。

这样就能避免异步状态更新导致的旧值捕获问题,保证每次点击按钮都能正确更新进度状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:05:42