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

如何实现动态向上滑入过渡?React多步骤手风琴式表单的动态重构方案及替代实现建议

Refactoring to a Dynamic Multi-Step Accordion

Your current code has a lot of repetitive hardcoding—let's fix that by turning your steps into data and rendering components dynamically. Here's how to do it:

Step 1: Define Step Data

First, create an array of step objects that holds all the info needed for each step (ID, label, whether it's the final step):

const steps = [
  { id: 1, label: "Step 1", isLast: false },
  { id: 2, label: "Step 2", isLast: false },
  { id: 3, label: "Step 3", isLast: false },
  { id: 4, label: "Step 4", isLast: true },
];

Step 2: Refactor Component Logic

Replace the hardcoded components with a map over the steps array. We'll also make the button handlers dynamic to work with any step:

import * as React from "react";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Slide from "@mui/material/Slide";

export default function CustomizedAccordions() {
  const [activeStep, setActiveStep] = React.useState(1);

  const steps = [
    { id: 1, label: "Step 1", isLast: false },
    { id: 2, label: "Step 2", isLast: false },
    { id: 3, label: "Step 3", isLast: false },
    { id: 4, label: "Step 4", isLast: true },
  ];

  const handleNext = (currentStepId) => {
    if (currentStepId < steps.length) {
      setActiveStep(currentStepId + 1);
    } else {
      // Handle form submission here
      console.log("Form submitted successfully!");
      setActiveStep(1); // Reset to first step after submit (adjust as needed)
    }
  };

  const handleBack = (currentStepId) => {
    if (currentStepId > 1) {
      setActiveStep(currentStepId - 1);
    }
  };

  return (
    <div>
      {steps.map((step) => (
        <Slide
          key={step.id}
          direction="up"
          in={activeStep >= step.id} // Show slide if we're on or past this step
          mountOnEnter
          unmountOnExit
        >
          <Accordion
            expanded={activeStep === step.id}
            onChange={() => setActiveStep(step.id)}
          >
            <AccordionSummary
              aria-controls={`panel${step.id}d-content`}
              id={`panel${step.id}d-header`}
            >
              <Typography>{step.label}</Typography>
            </AccordionSummary>
            <AccordionDetails style={{ display: "flex", gap: "1rem" }}>
              {/* Back button: only show for steps after the first */}
              {step.id > 1 && (
                <Button variant="outlined" onClick={() => handleBack(step.id)}>
                  Back
                </Button>
              )}
              {/* Next/Submit button: switch based on if it's the last step */}
              {!step.isLast ? (
                <Button variant="contained" onClick={() => handleNext(step.id)}>
                  Next
                </Button>
              ) : (
                <Button
                  variant="contained"
                  color="success"
                  onClick={() => handleNext(step.id)}
                >
                  Submit
                </Button>
              )}
            </AccordionDetails>
          </Accordion>
        </Slide>
      ))}
    </div>
  );
}

This refactor:

  • Eliminates all hardcoded conditions and component duplication
  • Makes it trivial to add/remove steps by updating the steps array
  • Uses dynamic handlers that work with any step ID
  • Preserves your original slide-in animation behavior

Alternative Approaches for Multi-Step UIs

If you're open to other ways to build this kind of component, here are a few options:

1. Material UI Stepper

Material UI has a built-in Stepper component designed specifically for multi-step workflows. It handles step navigation and visual state out of the box, and you can pair it with accordions or direct content rendering:

// Example snippet using Stepper
import Stepper from "@mui/material/Stepper";
import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel";

// Inside your component:
<Stepper activeStep={activeStep}>
  {steps.map((step) => (
    <Step key={step.id}>
      <StepLabel>{step.label}</StepLabel>
    </Step>
  ))}
</Stepper>
// Render content for the active step below

2. State Machines (XState)

For complex flows with validation, branching, or conditional steps, using a state machine library like XState makes your logic more predictable and maintainable. It explicitly defines allowed transitions between steps and handles edge cases (like blocking navigation if a step is invalid).

3. Custom CSS Transitions

If you want full control over animations, create your own slide-in effects using CSS classes and React state. Toggle classes based on the active step to trigger transitions:

.step-slide {
  transition: transform 0.3s ease-in-out;
  transform: translateY(100%);
}

.step-slide.active {
  transform: translateY(0);
}

4. React Router for Route-Based Steps

If each step needs its own URL (for sharing or bookmarking), use React Router to map each step to a route. You can add transition animations between routes using libraries like react-transition-group.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:17:38