Simple structure to write forms in React with Formik
Table of Contents
Introduction
I wanted to share how I use Formik to write forms in my react code. I expect you've already heard and tried Formik
before so we can discuss mostly component structure here. This article is not intended to be a full Formik
tutorial. Formik docs has all the information you need.
useFormik hook
Out of different ways you can use Formik
to create forms, the useFormik
hook is the only thing I've ever needed. It takes a config
object and returns an object with all the tools we need to create forms.
The minimum values you need to add in the config
object are:
initialValues
object - Values that go inside the form fields when the form is rendered. This is the initial state of the form.onSubmit
function - Receives the final values when the user submits the form. Use this function to clean up thevalues
if needed before sending it to the server.validate
function - Run validations on values and return errors. There is an alternativevalidationSchema
which you can use to define a schema using Yup object schema validation library.
const formik = useFormik({
initialValues,
onSubmit,
validate,
});
const {
values,
errors,
handleSubmit,
setFieldValue,
...andManyOthers
} = formik;
Component Structure
I always use the good old two-level container & presentational
structure for forms.
- A container component where I define all the
config
that goes inuseFormik(config)
hook. - A presentational component that receives this
config
prop and renders the form component.
This structure is a general style to write reusable components. This works even better for forms by creating separate containers for create
and edit
items but uses the same <Form />
component that displays the form.
For example, a user account form structure looks like this.
<CreateUserFormContainer />
<UpdateUserFormContainer />
<UserForm />
validate
function or validationSchema
goes in another file and imported into form containers.
Even if you don't need both create
and edit
, writing a form container keeps things clear in large forms.
If we are using both forms, I also send an extra isNew
prop to <UserForm />
to know whether it's a create
form or an edit
form. This helps to display correct error messages and other text.
User account form
Here's the CodeSandbox Link to see the code for a sample User account form along with some utils and validations.
Final Thoughts
Although we've only needed the useFormik
hook, if you want to create custom fields using Formik elements like <Field>
, <ErrorMessage>
, useFormik
won't work. So, be sure to check useFormik docs to see what are you missing by using the useFormik
hook.
If you find yourself writing too many conditionals in JSX to use the same <Form />
for both create
and edit
or there are a lot of differences in form fields in create
and edit
forms, it's time to separate them in different components.
You never need to store form data in a global state especially using state-management libraries like Redux or MobX.