Member preview

Formik For React: A Dive Into Field Arrays

Let’s take a look at the <FieldArray /> Object of Formik

Like myself, you may be interested in the Formik form management package of React, and would like to become super familiar with it to boost your form productivity. One of the features that is sure to help us in our quest for smooth form management is the <FieldArray />, which acts as a sort of array manager when dealing with lists in forms. Let’s dive into what this actually means when it comes to practical application.

As a pre-read, I have published an introduction on the Formik package, which can be read here, which may be useful if have not yet delved into Formik:

<FieldArray /> First Glance

What Formik does very well is form management behind the scenes, which in turn provides us with coherent objects to work with, that are injected through various handler functions of a Formik object’s props.

FieldArray is no different. It contains a render prop where we define our form markup from an array of values, via an embedded function.

What Formik gives us here is an arrayHelpers object that is injected as an argument of this function, that allows us to manage our array. (We will explore what exactly arrayHelpers is and how to use it further down).

From here we can utilise it to manage our FieldList.

What does this setup look like? Like this:

let myList = ['value1', 'value2', 'value3'];
<Form>
<FieldArray
name="categories"
render={arrayHelpers => (
          //loop through myList / any object to define our form.
)}
/>
</Form>

<FieldArray /> does not contain markup in and of itself, but instead acts as a utility for us to get our jobs done quickly and efficiently when it comes to managing form lists.

As you may have guessed, our list needs to be an array, for example:

//list of values
let vehicles = [
'car',
'motorcycle',
'airplane',
'rocket'
];
<Formik
initialValues={{vehicles: vehicles}}
...

For our array of strings here, the string values will be the value of our <Field /> at each index of the array.

What we can do is use the <Formik /> object’s initialValues prop to pass our list directly into Formik. From here Formik is totally aware of our list of vehicles, and <FieldArray /> can access them.

But we could just do all this without <FieldArray /> — map an object and render <Field /> for each one. What makes using <FieldArray /> beneficial? In other words, why does this article exist?

The answer is arrayHelpers.

How arrayHelpers Works

Now — as mentioned above, arrayHelpers is injected in our render prop function, and allows us to manage our array of values.

Looping through our array is where arrayHelpers become interesting.

As discussed, we can map our array, configure a Formik <Field /> at each index so we can manipulate its value, as well as use other metadata for any other markup we want to include. But, what we can also do on an index by index basis is include other elements to manage the array itself.

arrayHelpers contains utilities to mutate our values array in various ways, which when called, also update our form list in real time via Formik state changes.

This is where arrayHelpers become interesting. arrayHelpers contains a bunch of utility functions to manage our array of values, including:

  • push() — add a new item onto our array
  • insert(index, "whatToInsert"); — we can also insert an item to our array from a particular index.
  • remove(index) — remove a value at a particular index
  • swap(indexA, indexB) — We can swap 2 indexes (think drag and drop!)
  • move(fromIndex, toIndex) — Moves a value to another index of the array
  • unshift(item) — Insert a value at the beginning of our array, and return the resulting array length.
  • pop — remove the end value of our array and return its value
  • replace(index, "value") — replaces a value at a certain index.

I was originally going to just list the “main” utilities of arrayHelpers, but you will find that they all play a role in your projects, just give it a bit of time!

Ok, so now we are aware of these useful helpers, how are they used in cold hard JSX? Here is an example:

<div>         
{formProps.values.vehicles.map((vehicle, index) => (
<div key={index}>

//edit the value here
<Field name={`vehicles.${index}`} />

//remove this vehicle
<button
type="button"
onClick={() => arrayHelpers.remove(index)}
>
Remove
</button>
      
//add a new empty vehicle at this position
<button
type="button"
onClick={() => arrayHelpers.insert(index, '')}
>
Add Vehicle at this index
</button>
</div>
))}

   //add a new empty vehicle at the end of the list
<button
type="button"
onClick={() => arrayHelpers.push('')}
>
Add Vehicle
</button>
</div>

Validation with FieldArrays

Just like our other elements in a Formik form, we can refer to our validation prop or validationSchema prop (with Yup) when validating FieldArray elements.

The Formik documentation recommends that we check the type of our errors as they have to be strings in order to be displayed. One way to do this is to explicitly test within our FieldArray render:

const VehicleArrayErrors = errors => 
typeof errors.vehicles === 'string'
? <div>{errors.vehicles}</div>
: null;

Another way to nest error messages is to create a custom ErrorMessage component:

import { Field, getIn } from 'formik';  
const ErrorMessage = ({ name }) => (
<Field
name={name}
render={({ form }) => {
const error = getIn(form.errors, name);
const touch = getIn(form.touched, name);
return touch && error
? error
: null;
}}
/>
);
<ErrorMessage name="vehicles[0].name" />;

What this component does is check whether an error exists for a particular field. We are using a <Field /> component in order to access our form metadata.

If the particular field we are checking has been touched, and if there is indeed an error, the error is returned and rendered.

If either of these requirements is not satisfied, null is returned.

Abstracting FieldArray rendering

As your forms grow you may wish to separate the render method from the <Formik /> markup. Up until this point we have been using the render prop to display our FieldArray, however, we also have access to the component prop, allowing us to define the FieldArray in a separate component:

...
<FieldArray
name="friends"
component={MyDynamicForm}
/>
...

export const MyDynamicForm = ({move, swap, push, insert, unshift, pop, form }) => (  
<Form>
{form.values.vehicles.map((vehicle, index) => (
//define our array like before
))}
</Form> );

Notice here that we are injecting arrayHelpers on an individual method basis, rather than the entire arrayHelpers object. This may be preferable if we are only using one or two of the arrayHelper methods, slightly cleaning up our syntax.

The official Formik documentation on FieldArray can be found at https://jaredpalmer.com/formik/docs/api/fieldarray.

Even though this documentation is not great, it may indeed improve in the future as Formik continues to evolve and rolls out new features. Nevertheless, it is a resource worth noting.

To conclude on the FieldArray, below is a gist outlining our example. Copy it into your projects to get started with <FieldArray />: