Authentication with React Form Wizard and Nodejs - Part 2
Published: 2022-03-12 15:07:21

This tutorial is a continuation of ['Authentication with React From Wizard and Nodejs - Part 1](https://dev.to/paulvermeer2021/authentication-with-react-from-wizard-and-nodejs-part-1-163l). In the previous part the backend and Redux Store was coded. It's now time to build the form wizards with material-UI, React Hooks and Yup. 

**(3) Sign Up Form Wizard with Context Store**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i6vb1dgtuav5x3alf8ca.png)

The first thing we need to do is to define the main form element field, a Material-UI text field. Create a folder named <em>elements</em> inside your <your-app-name>/src directory and add <em>TextField.js</em>.

{% gist 
https://gist.github.com/full-stack-concepts/51f2df63c064c4b9d3135c72c6d64738
%}

You can now use this element to code the inputs or fields that will be used in the hooks form. Create an <em>inputs</em> folder in <your-app-name>/src directory and add these fine files: 

<em>Email.js</em>
```javascript
import TextField from '../elements/TextField';

export const Email = ({label, control, register, onChangeHandler, onBlurHandler}) => <TextField
    fieldName={`email`}
    fieldType={`email`}
    label={`Email`}
    control={control}
    register={register}
    required={true}
    onChangeHandler={onChangeHandler}
    onBlurHandler={onBlurHandler}
/>
```
<em>Password.js</em>
```javascript
import TextField from '../elements/TextField';

export const Password = ({label, control, register, onChangeHandler, onBlurHandler}) => <TextField
    fieldName={`password`}
    fieldType={`password`}
    label={`Password`}
    control={control}
    register={register}
    required={true}
    onChangeHandler={onChangeHandler}
    onBlurHandler={onBlurHandler}
/>
```
**Signin Components**

Now create a <em>components</em> folder in <your-app-name>/src dir and then a new subfolder named <em>SigninStepper</em>. 

Our main component is Stepper.js which imports it's children dynamically, depending on the form step. Each form step should be validated as soon as all fields are touched. If the step is valid the user should be allowed to progress to the next step. All components share state through React Context.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tpyz87b9l2aokx34x0lg.png)

Let's start with coding a local Context Store, <em>FormContext.js</em>

```javascript
import {createContext, useState} from 'react';
export const FormContext = createContext();
export const FormContextProvider = ({children}) => {	
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [step1, setStep1Finished ] = useState(false);	
  const [finished, setFinished] = useState(false);
  const formContextValues = {    			
    email, setEmail,  
    password, setPassword,
    step1, setStep1Finished, 		
    finished, setFinished
  }; 	
  return (<div>
    <FormContext.Provider value={formContextValues}>
      {children}
    </FormContext.Provider>
   </div>);
}
```

Then wrap your provider like so in <em>components/SigninStepper/index.js</em>: 
```javascript
import React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { green, blue } from '@mui/material/colors';
import { FormContextProvider } from './FormContext';
import Stepper from './Stepper';
const theme = createTheme({
  palette: {
    mode: 'dark',
    primary: {
      main: blue[500],
    },
    secondary: {
      main: green[500],
    },
  },
});

/**
 * Form Context Store
 */
function SigninStepper() {	
  return (
    <ThemeProvider theme={theme}>
      <FormContextProvider>              
        <Stepper />
      </FormContextProvider>
     </ThemeProvider>
  );
}

export default SigninStepper;
```

**The Stepper Component**
The 'high order component'is a [@Mui vertical stepper](https://mui.com/components/steppers/#vertical-stepper) and extended with:
(1) The FormContext store.
```javascript
    const {
        email, password, step1, finished       
    } = useContext(FormContext);
```
(2) Load dynamic content with useEffect hook.
```javascript
   useEffect(() => {       
        let Component;
        const load = async () => {
            const StepView = `Step${activeStep+1}`;
            if(!components[StepView]) {             
                const { default:View } = await import(`./Steps/${StepView}`)
                Component = <View 
                    FormContext={FormContext} 
                />;             
                setComponent({...components, [StepView]: Component })
                setView(Component);
            } else {               
                setView(components[StepView]);
            }
        }
        load();       
    }, [activeStep]); 
```
(3) Monitor progress with hook useEffect
```javascript
useEffect(() => {    
  setSolutionProvided(false);
  if (activeStep === 0 && step1) {
    setSolutionProvided(true);
  }       
  if (activeStep === steps.length - 1 && password && finished) {
    setSolutionProvided(true);
  }       
}, [activeStep, email, password, step1, finished]);
```
(4) Monitor result of our Redux login action with another useEffect hook.
```javascript
useEffect(() => {            
  if (status.success) {                             
    navigate('/dashboard');
  }       
  if (status.error) {                     
    setActiveStep(steps.length-1);
    toast.error(status.message);                          
  }
  dispatch(clearFetchStatus());       
}, [status, dispatch, navigate]);
```
The result may look like:

{% gist 
https://gist.github.com/full-stack-concepts/cdd59be9f76693e695662bae4cfd0fa8
%}

Let's now create the <em><your_app_name>/src/components/SigninStepper/Steps</em>directory where the different form steps will be stored.

<em>Step1.js</em>
{% gist 
https://gist.github.com/full-stack-concepts/c245fe466c0eb0903ef091fa61e5c169
%}

Whenever the user add a value to the email field the onChangeHandler function is triggered and (1) injects the event value into the form state of React Hook Form, (2) triggers validation and (3) saves the value in the Context Store.

As soon as Yup through React Hook Form signals that the form is valid - the <em>isValid</em> param of formState - the high order component (Stepper.js) is informed though an useEffect hook that the step is finished and the user may proceed to the next one.

<em>Step2.js</em>
{% gist 
https://gist.github.com/full-stack-concepts/af0f1557f814806c50f172195a5d3043
%}

This step uses the same logic. Whenever a user browses between validated steps the useEffect hook is used to load any value saved in the Context Store.

**(4) Sign Up form wizard with Context Store**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ix19t966xifkbjzo0gj3.png)

To create this form wizard you only have to repeat the steps used to create the Sign in Form Wizard as it uses the same building blocks:
(1) Create a folder named <em>SigninStepper</em>
(2) Code the Context Store
(3) Wrap it around Stepper.js in index.js
(4) Code Stepper.js
(5) Code the steps with inputs <em>Email</em> and <em>Pasword</em>

The app is now ready to be tested. Open two terminals and start the server and client with **npm run start**. 

More examples can be found in the [repo](https://github.com/full-stack-concepts/react-form-wizard).