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

React复杂组件多实例创建咨询:Program与Exercise嵌套实例

Hey Dan, sounds like you're building a nested dynamic component system—totally get the need for an elegant, scalable approach here. Let me break down a clean solution I’ve used for similar nested creation flows:

Core Approach: Nested State Management + Reusable Components

The key is to structure your state to mirror the nested component hierarchy, then build reusable, self-contained components that handle their own interactions while syncing with the parent state.

Step 1: Define a Clear Nested State Structure

Start with a state array where each Program object contains its own array of Exercise objects. This keeps your data organized and easy to update:

// Example using React useState (adjust for your framework)
const [programs, setPrograms] = useState([
  {
    id: `program-${Date.now()}`, // Unique ID for each program
    name: '',
    description: '',
    exercises: [
      {
        id: `exercise-${Date.now()}`, // Unique ID for each exercise
        name: '',
        sets: 3,
        reps: 10,
        restPeriod: 60
      }
    ]
  }
]);

Step 2: Build Reusable Child Components

Split your UI into small, focused components that accept props for data and interaction handlers. This keeps your code DRY and easier to maintain:

ProgramCard Component

Handles rendering a single program and its exercises, plus controls to add/remove exercises or delete the program:

const ProgramCard = ({ program, onUpdateProgram, onAddExercise, onRemoveProgram }) => {
  return (
    <div className="program-card">
      <input
        type="text"
        value={program.name}
        onChange={(e) => onUpdateProgram(program.id, 'name', e.target.value)}
        placeholder="Program Name"
      />
      <textarea
        value={program.description}
        onChange={(e) => onUpdateProgram(program.id, 'description', e.target.value)}
        placeholder="Program Description"
      />

      <h3>Exercises</h3>
      {program.exercises.map(exercise => (
        <ExerciseItem
          key={exercise.id}
          exercise={exercise}
          programId={program.id}
          onUpdateExercise={onUpdateExercise}
          onRemoveExercise={onRemoveExercise}
        />
      ))}
      
      <button onClick={() => onAddExercise(program.id)}>Add Exercise</button>
      <button onClick={() => onRemoveProgram(program.id)}>Delete Program</button>
    </div>
  );
};

ExerciseItem Component

Renders a single exercise with editable fields:

const ExerciseItem = ({ exercise, programId, onUpdateExercise, onRemoveExercise }) => {
  return (
    <div className="exercise-item">
      <input
        type="text"
        value={exercise.name}
        onChange={(e) => onUpdateExercise(programId, exercise.id, 'name', e.target.value)}
        placeholder="Exercise Name"
      />
      <input
        type="number"
        value={exercise.sets}
        onChange={(e) => onUpdateExercise(programId, exercise.id, 'sets', parseInt(e.target.value))}
        min="1"
      />
      <button onClick={() => onRemoveExercise(programId, exercise.id)}>Remove</button>
    </div>
  );
};

Step 3: Implement CRUD Logic for Nested Data

Write helper functions to update the state in an immutable way (critical for reactivity in frameworks like React/Vue):

// Add a new empty program
const addProgram = () => {
  setPrograms(prevPrograms => [
    ...prevPrograms,
    {
      id: `program-${Date.now()}`,
      name: '',
      description: '',
      exercises: [
        { id: `exercise-${Date.now()}`, name: '', sets: 3, reps: 10, restPeriod: 60 }
      ]
    }
  ]);
};

// Update a program's property (name, description, etc.)
const onUpdateProgram = (programId, key, value) => {
  setPrograms(prevPrograms => 
    prevPrograms.map(program => 
      program.id === programId ? { ...program, [key]: value } : program
    )
  );
};

// Add an exercise to a specific program
const onAddExercise = (programId) => {
  setPrograms(prevPrograms => 
    prevPrograms.map(program => 
      program.id === programId 
        ? { ...program, exercises: [...program.exercises, { id: `exercise-${Date.now()}`, name: '', sets: 3, reps: 10, restPeriod: 60 }] }
        : program
    )
  );
};

// Update an exercise's property
const onUpdateExercise = (programId, exerciseId, key, value) => {
  setPrograms(prevPrograms => 
    prevPrograms.map(program => 
      program.id === programId 
        ? { 
            ...program, 
            exercises: program.exercises.map(exercise => 
              exercise.id === exerciseId ? { ...exercise, [key]: value } : exercise
            )
          }
        : program
    )
  );
};

Bonus Optimizations for Scalability

  • Use proper unique IDs: Replace Date.now() with a UUID library (like uuid) in production to avoid collisions.
  • Extract state logic: Move all CRUD functions into a custom hook (e.g., useProgramManager) to keep your parent component clean.
  • Add validation: Include checks to prevent empty program/exercise names before saving, or enforce minimum set/reps values.
  • Add reordering: If users need to reorder programs/exercises, integrate a drag-and-drop library (like react-beautiful-dnd for React) for a smoother UX.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:25:17