Building an Advanced Multistep Form with React Hook Form
In this blog post, we'll demonstrate how to create an advanced multistep form using React Hook Form, a popular form library for React. React Hook Form aims to minimize re-rendering and provides a better developer experience by leveraging hooks and the native HTML form behavior.
Creating the Form Context
To manage our form data, we'll create a custom form context. This context will store the form data and provide a function to update it.
// src/FormContext.js
import { createContext, useContext, useState } from "react";
const FormContext = createContext();
export const useFormContext = () => {
return useContext(FormContext);
};
export const FormProvider = ({ children }) => {
const [formData, setFormData] = useState({});
const updateFormData = (updatedData) => {
setFormData((prevData) => ({ ...prevData, ...updatedData }));
};
return (
<FormContext.Provider value={{ formData, updateFormData }}>
{children}
</FormContext.Provider>
);
};
Creating the Form Steps
Now, let's create three form steps: Personal Info, Employment, and Review.
Personal Info Step
// src/steps/PersonalInfo.js
import { useForm } from "react-hook-form";
import { useHistory } from "react-router-dom";
import { useFormContext } from "../FormContext";
export const PersonalInfo = () => {
const { register, handleSubmit } = useForm();
const { updateFormData } = useFormContext();
const history = useHistory();
const onSubmit = (data) => {
updateFormData(data);
history.push("/employment");
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="name">Name</label>
<input {...register("name")} id="name" required />
</div>
<div>
<label htmlFor="email">Email</label>
<input {...register("email")} id="email" required />
</div>
<button type="submit">Next</button>
</form>
);
};
Employment Step
// src/steps/Employment.js
import { useForm } from "react-hook-form";
import { useHistory } from "react-router-dom";
import { useFormContext } from "../FormContext";
export const Employment = () => {
const { register, handleSubmit } = useForm();
const { updateFormData } = useFormContext();
const history = useHistory();
const onSubmit = (data) => {
updateFormData(data);
history.push("/review");
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="company">Company</label>
<input {...register("company")} id="company" />
</div>
<div>
<label htmlFor="position">Position</label>
<input {...register("position")} id="position" />
</div>
<button type="submit">Next</button>
</form>
);
};
Review Step
// src/steps/Review.js
import { useFormContext } from "../FormContext";
export const Review = () => {
const { formData } = useFormContext();
return (
<div>
<h2>Review</h2>
<pre>{JSON.stringify(formData, null, 2)}</pre>
<p>Once you're satisfied with the data, you can submit the form to a backend service or save it to a local storage.</p>
</div>
);
};
Setting Up Routes
Now, let's create a Router
component to handle navigation between the steps:
// src/Router.js
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { PersonalInfo } from "./steps/PersonalInfo";
import { Employment } from "./steps/Employment";
import { Review } from "./steps/Review";
export const Router = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={PersonalInfo} />
<Route path="/employment" component={Employment} />
<Route path="/review" component={Review} />
</Switch>
</BrowserRouter>
);
};
Updating App.js
Finally, wrap the Router
component in App.js
with the FormProvider
:
// src/App.js
import { FormProvider } from "./FormContext";
import { Router } from "./Router";
function App() {
return (
<div className="App">
<FormProvider>
<Router />
</FormProvider>
</div>
);
}
export default App;
Conclusion
In this blog post, we've built an advanced multistep form using React Hook Form and React Router. We've also created a custom form context to manage form data throughout the steps. By following this approach, you can create complex multistep forms with ease, while leveraging the benefits of React Hook Form.
As a potential enhancement, you could integrate with third-party libraries like Tutim for schema-based implementation including validation, form persistence, conditional rendering, save draft, and more.
Top comments (0)