Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material UI Stepper not keeping state when move next or back

I have Material UI Stepper Component. I am rendering stepper dynamically on ADD Button. Each step includes some form including TextFields, SelctBox etc. When I fill the form on first step and click Next to fill form on next screen and if I come back on first step by clicking BACK Button I am loosing data filled in first step.

So the question is - Is there way to keep the data in the Form Fields while we're changing steps ?

I tried below but not understanding how to store state on parent component.

export default function FeaturesSteppers(props) {

.......
const [stepperState, setStepperState] = React.useState({});

const getStepContent = step => {
switch (step) {
  case 0:
    return <Profile 
      index={index} 
      form={form} 
      stepperState={stepperState}
      onUpdateStepperState={handleUpdateStepper}
    />;
  case 1:
    return "< Step1 />";
  case 2:
    return "< Step2 />";
  case 3:
      return "< Step3 />";
  default:
    return "Unknown step";
}
}

.........

const handleUpdateStepper = (data) => {
  console.log('INSIDE Handle Update')
  setStepperState(...)
};

I am not sure what should I return from Profile.js and how to use it on Parent Component.

like image 877
ppb Avatar asked Sep 01 '25 10:09

ppb


2 Answers

The issue with your code is that once you go from step #0 to step #1 - the <Profile /> component no longer exists, and so is all if it's child components and their internal states. You can save the internal state into a some global state/context that will reload the content once the component will get into the DOM again, but instead you can just render all of the steps, but hide the non-relevant ones:

const getStepContent = step => {

    const allSteps = [
        <Profile 
            index={index} 
            form={form} 
            stepperState={stepperState}
            onUpdateStepperState={handleUpdateStepper}
        />,
        <Step1 />,
        <Step2 />,
        <Step3 />
    ];

    return (
        <>
            {allSteps.map(
                (stepCmp, index) => {
                    return <div hidden={index !== step}>{stepCmp}</dv>
                })
            }
        </>
    );
}

The down-side here is that you do need to render all the components before actually having them displayed.

like image 186
Dekel Avatar answered Sep 03 '25 00:09

Dekel


Your question is 7 months old already and I had the same issue which led me here. For the sake of those who'll need this later, here is how I got mine fixed.

  • You have to make sure that all <TextField/> input value is managed from your parent state.
  • You must pass down the value of each <TextField /> as a prop to your child component.

Consider the example below:

   function Parent(){
      const [ values, setName ] = React.useState({
         name: "",
         email: "",
      });
      
      return (
         <Step1 inputValues = { values } />
      )
   }

Then your child component will look like this:

   function Step1({ inputValues }){      
      return (
         <div>
            <TextField value={ inputValues.name } />
            <TextField value={ inputValues.email } />
         </div>
      )
   }

Your data will persist if you navigate away and back to to stepper index.

like image 25
Olawale Oladiran Avatar answered Sep 03 '25 00:09

Olawale Oladiran