DEV Community

No Face
No Face

Posted on

Easy Multi-Page Form with React-Router and React-Hook-Form

In this tutorial, I'll be showing you how to create a multi-page form – consisting of a Form page, Confirm / Review page, and Complete page only using react-router and react-hook-form.

1. First, let's create our pages/components.

// Form

const Form = () => {
  return (
    <div>
      <form onSubmit={onSubmit}>
        <div>
          FirstName: <input type="text" />
        </div>
        <div>
          LastName: <input type="text" />
        </div>
        <div>
          Gender:
          <input type="radio" value="male" /> Male
          <input type="radio" value="female" /> Female
        </div>
        <div>
          Country:
          <select>
            <option value="USA">USA</option>
            <option value="Canada">Canada</option>
            <option value="India">India</option>
          </select>
        </div>
        <button type="submit">Confirm</button>
      </form>
    </div>
  );
};
export default Form;
Enter fullscreen mode Exit fullscreen mode
// Confirm

const Confirm = () => {
  return (
    <div>
      <p>firstName: </p>
      <p>lastName: </p>
      <p>Gender: </p>
      <p>Country: </p>
      <button>back</button>
      <button>Submit</button>
    </div>
  );
};
export default Confirm;
Enter fullscreen mode Exit fullscreen mode
// Complete

const Complete = () => {
  return (
    <div>
      <p>Registration successful!</p>
    </div>
  );
};
export default Complete;
Enter fullscreen mode Exit fullscreen mode

2. Next, by using react-hook-form's useForm we will get the form data from our Form component.

const Form = () => {
  const { register, handleSubmit } = useForm();

  const onSubmit = handleSubmit((data) => {
    // logs form data
    console.log(data);
  });

  return (
    <div>
      <form onSubmit={onSubmit}>
        <div>
          FirstName: <input type="text" {...register("firstName")} />
        </div>
        <div>
          LastName: <input type="text" {...register("lastName")} />
        </div>
        <div>
          Gender:
          <input type="radio" value="male" {...register("gender")} /> Male
          <input type="radio" value="female" {...register("gender")} /> Female
        </div>
        <div>
          Country:
          <select {...register("country")}>
            <option value="USA">USA</option>
            <option value="Canada">Canada</option>
            <option value="India">India</option>
          </select>
        </div>
        <button type="submit">Confirm</button>
      </form>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

This should show the form data in console on submit.

// output would be something like this
{
 firstName: "John"
 lastName: "Doe"
 gender: "male"
 country: "Canada"
}
Enter fullscreen mode Exit fullscreen mode

3. Pass the data to our Confirm Page using react-router's useNavigate state prop.

const Form = () => {
  const navigate = useNavigate();
  const { register, handleSubmit } = useForm();

  const onSubmit = handleSubmit((data) => {
    // Pass the form data on state prop when navigating to confirm page.
    navigate("/confirm", { state: data });
  });
 ...
Enter fullscreen mode Exit fullscreen mode

4. Displaying data on Confirm page -- this time using react-router's useLocation.

const Confirm = () => {
  // Get current location's state
  const { state } = useLocation();

  // Display the data using `state.{input name}`
  // In this case, input name will be the value we set on input register from the Form component
  return (
    <div>
      <p>firstName: {state.firstName}</p>
      <p>lastName: {state.lastName}</p>
      <p>Gender: {state.gender}</p>
      <p>Country: {state.country}</p>
      <Link to="/" state={state}>
        <button>back</button>
      </Link>
      <Link to="/complete">
        <button>Submit</button>
      </Link>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Note that we passed the form data again on this line.

...
      <Link to="/" state={state}>
        <button>back</button>
      </Link>
...
Enter fullscreen mode Exit fullscreen mode

This is because when the user clicks the back button, we can "remember" the current input data and we would be able to display it to our form.

To do this, we will again get the form data values from the locations state prop and ww will display it as the defaultValues using useForm's reset.

const Form = () => {
  const navigate = useNavigate();
  const { state } = useLocation();
  const { register, reset, handleSubmit } = useForm();

  const onSubmit = handleSubmit((data) => {
    navigate("/confirm", { state: data });
  });

  useEffect(() => {
    // reset the entire form and set the defaultValues with state value
    reset(state);
  }, []);
...
Enter fullscreen mode Exit fullscreen mode

We're done!

You can find the complete source in this link.


Discussion (0)