Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
March 18, 2021 01:57 pm GMT

How to create simple multi-step sign in with validation

Introduction

Let's say you need to create a multi-step login form like in gmail. You are using react and the global storage (redux, mobx) for development, and you want to isolate components from each other in order to reuse them in the future. Besides this, you need to add validation to each step. In this article I will show the simplest and most correct, in my opinion, solution. Complete solution you can check here

Dependencies

First of all, we need a library for processing the form, in my opinion the best solution is react-hook-forms (https://react-hook-form.com/), the site describes in great detail why this is an excellent solution, i will add on my own that this library has powerful functionality (validations, quick integrations, controller mechanism) and good documentation.
For validation we will use the yup library, it's very powerful and popular library
For global storage i will use little-state-machine, because it's very simple solution and built on a flux architecture. But you can use redux or mobx
To integrate yup validation schemas with react-hook-form you will also need @hookform/resolvers package.

Let's code

Project Structure

The example uses the following project structure

  • steps <- here will be all form steps
    • Congrats.js <- final step, if sign in is successed
    • Email.js <- First step, enter email to continue sign in
    • Password.js <- Second step, enter password to sign in
  • store
    • actions.js <- include all actions, in my case only one for update form state
    • index.js <- include app state, in my case only form state
  • App.js <- Main component, in my case include form logic
  • index
  • App.css <- App styles

About store

In the storage we will store information about the step of the form and email data. Let's add this information in store/index.js

const state = {  step: "Email",  email: ""};export default state;

Now let's add an action to update the form in actions.js

const updateFormState = (state, payload) => {  return {    ...state,    ...payload  };};export default updateFormState;

Let's add our storage to the application in index.js

import { StrictMode } from "react";import ReactDOM from "react-dom";import App from "./App";import { StateMachineProvider, createStore } from "little-state-machine";import store from "./store";// create out global form statecreateStore(store);const rootElement = document.getElementById("root");ReactDOM.render(  <StrictMode>    <StateMachineProvider>      <App />    </StateMachineProvider>  </StrictMode>,  rootElement);

Base logic

The logic for switching the form, as well as its handlers, will be in App.js (for example only). We need to connect the store to the component in order to receive information about the form and update it.

import "./styles.css";import { useStateMachine } from "little-state-machine";import updateFormState from "./store/actions";// Here we import form stepsimport EmailStep from "./steps/Email";import CongratsStep from "./steps/Congrats";import PasswordStep from "./steps/Password";export default function App() {  // use hook for getting form state and actions  const { state, actions } = useStateMachine({ updateFormState });  // form handler for email step  const emailFormHandle = ({ email }) => {    actions.updateFormState({      email: email,      step: "Password"    });  };  // form handler for password step  const passwordFormHandle = ({ password }) => {    actions.updateFormState({      step: "Congrats"    });  };  // sign out handler  const signOutHandle = () => {    actions.updateFormState({      step: "Email"    });  };  return (    <div>      {state.step === "Email" && (        <EmailStep email={state.email} onSubmit={emailFormHandle} />      )}      {state.step === "Password" && (        <PasswordStep onSubmit={passwordFormHandle} />      )}      {state.step === "Congrats" && (        <CongratsStep email={state.email} onSignOut={signOutHandle} />      )}    </div>  );}


javascript
Form step components are isolated from each other as much as possible, and can be reused in other parts of the application. All you need is only add default values, if they exists (for email step) and form handler function.

Steps

Email

The email entry step is the first step for user authorization. It is necessary to check the validity of the entered email, and remember it in case the user at the step with the password wants to go back and change it a little. This may seem very far-fetched, but when there are a lot of inputs in form, saving their state is very useful to save the user's time. Code with comments over here:

import { useForm } from "react-hook-form";// import our validation libraryimport * as yup from "yup";// import integration libraryimport { yupResolver } from "@hookform/resolvers/yup";import cn from "classnames";// validation schemaconst Schema = yup.object().shape({  // it says here that we want to check the input with the name email for the fact that the user will pass a string and this string matches email, you can change validation error message by changing text in email function argument  email: yup.string().email("Enter valid email please")});const EmailStep = (props) => {  // get form on Submit handler from parent component  const { onSubmit, email } = props;  // apply validations schema to react-hook-form form object  const { errors, register, handleSubmit } = useForm({    resolver: yupResolver(Schema),    // if user input his email before we can paste it to input as default value    defaultValues: {      email    }  });  //  you can check all validations errors in console  console.log(errors);  return (    <form onSubmit={handleSubmit(onSubmit)}>      <div className="form-group">        <h2>Enter your email</h2>      </div>      <div className="form-group">        {/* check validation errors */}        {errors.email && (          <h4 className="invalid-msg">{errors.email.message}</h4>        )}        <input          // make input invalid if get email validation errors          className={cn(errors.email && "input-invalid")}          name="email"          ref={register}          placeholder="Your email"        />      </div>      <div className="form-group">        <button type="submit">Next</button>      </div>    </form>  );};export default EmailStep;

What you need to know:

  • Form validation will be apply after user click on submit button (Next button in my case), but you can change this behavior in form options
  • All validation errors are in the error object, which is generated by react-hook-form, the key is input name (email) and value is validation message (Enter valid email please)
  • You can use the default validation rules by react-hook-form form object, without any libraries, but yup is more powerful and flexible package.

Password step

The last step in user authorization. The password should be more that 6 symbols length and include Latin letters. The code is below:

import { useForm } from "react-hook-form";import * as yup from "yup";import { yupResolver } from "@hookform/resolvers/yup";import cn from "classnames";const Schema = yup.object().shape({  password: yup    .string()    .min(6, "Password is too short")    .matches(/[a-zA-Z]/, "Password can only contain Latin letters.")});const PasswordStep = (props) => {  const { onSubmit } = props;  const { errors, register, handleSubmit } = useForm({    resolver: yupResolver(Schema)  });  console.log(errors);  return (    <form onSubmit={handleSubmit(onSubmit)}>      <div className="form-group">        <h2>Enter your password</h2>      </div>      <div className="form-group">        {errors.password && (          <h4 className="invalid-msg">{errors.password.message}</h4>        )}        <input          className={cn(errors.password && "input-invalid")}          name="password"          type="password"          ref={register}          placeholder="Your password"        />      </div>      <div className="form-group">        <button type="submit">Sign In</button>      </div>    </form>  );};export default PasswordStep;

Final step

And finally let's show user congrats message

const CongratsStep = (props) => {  const { email, onSignOut } = props;  return (    <div className="form-group">      <h2>        Hello, {email}        <button onClick={onSignOut}>Sign Out</button>      </h2>      <img src="https://i.giphy.com/6nuiJjOOQBBn2.gif" alt="" />    </div>  );};export default CongratsStep;

Conclusion

That's all. We create isolated form steps, add default values for email value, add validation rules to every form step and use for this most powerful and popular packages (excluding little-state-machine).
If you interested i can show this examples with typescript, MUI and mobx or redux packages

P.S.

This is my first article, and english is not my native language, hope everything was clear and you had a pleasant time :) If you have problems with understanding the text (due to the fact that I do not know the language well), you can always look at my code, it says much more than any words


Original Link: https://dev.to/alex1998dmit/how-to-create-simple-many-step-form-with-validation-3g4f

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To