如何实现动态向上滑入过渡?React多步骤手风琴式表单的动态重构方案及替代实现建议
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
stepsarray - Uses dynamic handlers that work with any step ID
- Preserves your original slide-in animation behavior
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

