score:4

Accepted answer

You Component hierarchy seems good, I would like to add one thing to keep things together, like for steps you can create an Array inside a main component state like this

class Main extends React.Component{
    state = {
      ...OTHER_STATE_PROPERTIES,
      activeStep: 0 | 1| 2,
      steps: [{
        name: 'step-name',
        icon: 'icon-name',
        content: Form1 | Form2 | Form3, // this is optional, you can use getContent too
        data: {}
      }]
    }


    // pass this function as prop to every Form Component
    // We will talk about this function soon
    handleStepSubmit = (stepIndex, data) => {
      this.setState((prevState) => ({
        ...prevState,
        activeIndex: prevState.activeIndex + 1,
        steps: prevState.map((step, index) => {
          if(stepIndex !== index){
            return step; 
          }
          return {
            ...step,
            data
          }
        })
      }))
    }
    //... Other stuff

}

Now each Form should have its own state (so that only the form gets re-render on input changes) and form, where you can handle input and validate them and send it to parent component step using props, so we need to add a function in the parent component. handleStepSubmit function will only be called after validation of data on onSubmit call of form

How to validate data is up to you, you can use

default input attributes like,

  1. required
  2. min, max for number
  3. type (email)
  4. pattern

Validate State using JS logic

Use yup

Use Formik with yup

This is what I prefer by using formik you don't have to worry about onChange, validation and many more things, you can provide it validate prop where you can write validation logic yourself or validationSchema prop where just yup schema should be given, it will not allow if onSubmit to trigger if validation fails, you can also input attributes with it, if form is simple. We have to call handleStepSubmit on onSubmit

P.S.: It maintains a local state

What we have

At step 0 we will have

// I am omitting other stuff for understanding
state:{
   activeStep: 0,
   steps: [
     {data: {}},
     {data: {}},
     {data: {}},
   ]
}

When user submits Form 1 we will have

// I am omitting other stuff for understanding
state:{
   activeStep: 1,
   steps: [
     {data: formOneData},
     {data: {}},
     {data: {}},
   ]
}

and so one now when activeStep is 3 you will have all the validated data in the state, Horray!! High-Five! You can also data from previous steps in further step if required as we have it all in our parent component state.

Example:

Edit formik-example

score:-2

Save all form data to your states (even completed steps like current step). For validating your given data you should arrange a handleChange function for each field.

score:0

Basically, if I understand your question you would like

  • Create a multi-step form and do some validation of data on every step if fails then let the user refill the necessary data else move to next form data.

  • At every stage store in the state or store and once the user completes all step then you would like to work locally with that data.

Since you chose to work locally with those data I prefer redux-store to state because for obvious reasons like using the form data in business logic and other parts of the react

I hope Edit inspiring-babbage-81ejq this might be useful...

However, this is a basic structure and even I know there are lots of caveats and many things could be abstracted...

score:1

I would use a routing that points to the same component so you could store the old form in either your state/reducer/localStorage (in fact anything you want) and once the current step is ok I would simply navigate the user to the next one.

I have made a demo codesandbox with this logic.

I hope it helps


Related Query

More Query from same tag