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

使用useState实现嵌套数组训练计划滑块及回退按钮问题排查

训练计划滑块组件回退功能修复方案

问题排查

你的代码里回退按钮失效主要有两个核心问题:

  1. 拼写错误:currentCycle.exercises.lengh-1里的lengh是笔误,正确拼写是length,导致无法正确计算上一个训练组的最后一个动作索引。
  2. 逻辑漏洞:当innerIndex为0时,直接执行setOuterIndex(outerIndex-1),虽然后台按钮会被禁用,但函数内未做防御性检查;同时,回退到上一个训练组时,错误地使用了当前训练组的动作列表长度,而非上一个训练组的。

另外,边界判断逻辑可以简化,避免冗余的三元表达式。

修复后的完整代码

import React from 'react'
import { useState } from 'react';
import { useLocation } from 'react-router-dom'

const Workout = () => {
  const { state } = useLocation();
  const workout = state;

  const [ outerIndex, setOuterIndex ] = useState(0);
  const [ innerIndex, setInnerIndex ] = useState(0);

  const currentCycle = workout.cycles[outerIndex];
  const currentExercise = currentCycle.exercises[innerIndex];

  // 简化边界判断逻辑,语义化命名
  const isLastItem = innerIndex === currentCycle.exercises.length - 1 && outerIndex === workout.cycles.length - 1;
  const isFirstItem = innerIndex === 0 && outerIndex === 0;

  const nextIndex = () => {
    if (innerIndex === currentCycle.exercises.length - 1) {
      // 使用函数式更新避免异步state导致的索引偏差
      setOuterIndex(prev => prev + 1);
      setInnerIndex(0);
    } else {
      setInnerIndex(prev => prev + 1);
    }
  }
  
  const prevIndex = () => {
    // 防御性检查:已经是第一个元素时直接返回
    if (isFirstItem) return;
    
    if (innerIndex === 0) {
      // 回退到上一个cycle的最后一个exercise
      const prevCycle = workout.cycles[outerIndex - 1];
      setOuterIndex(prev => prev - 1);
      setInnerIndex(prevCycle.exercises.length - 1);
    } else {
      setInnerIndex(prev => prev - 1);
    }
  }

  return (
    <section id="workout-container">
      <h3>{workout.name}</h3>
      <aside>Orientações:{workout.workoutObs}</aside>
      <button onClick={prevIndex} disabled={isFirstItem}>prev</button>
      <button onClick={nextIndex} disabled={isLastItem}>next</button>
      <div className='cycle-item'>
        <h4>Ciclo {outerIndex+1} - {currentCycle.series}x</h4>
        <div className='exercise-item'>
          <p>{currentExercise.name}</p>
          <p>reps.:{currentExercise.reps}</p>
        </div>
        <p>{currentCycle.cycleObs}</p>
      </div>
    </section>
  )
}

export default Workout;

关键修改点说明

  1. 修正拼写错误:将lengh改为length,确保能正确获取动作列表的长度值。
  2. 函数式state更新:使用setState(prev => prev + 1)的形式更新索引,避免因React state异步特性导致的连续点击时索引计算错误。
  3. 回退逻辑修复:回退到上一个训练组时,先获取目标训练组的动作列表,再将innerIndex设为该列表的最后一个索引。
  4. 语义化边界判断:将原maxLimit/minLimit重命名为isLastItem/isFirstItem,用全等判断简化逻辑,提升可读性。
  5. 防御性检查:在prevIndex函数开头增加边界判断,避免无效的索引操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:20:47