Shopify-polaris form building with Formik, React-Final-Form and Yup
Tags: react, uncategorized, websites, finalform
Published: 2019-11-24 15:07:20

---
title: Shopify-polaris form building with Formik, React-Final-Form and Yup
published: true
date: 2019-11-24 13:56:40 UTC
tags: React,Uncategorized,Web Sites,final-form
canonical_url: https://ziatechblog.wordpress.com/2019/11/24/shopify-polaris-form-building-with-formik-react-final-form-and-yup/
---

### Disclaimer

_Not a code guide of either of the mentioned tools, but rather my experience using these, the problems I faced and the solution we adopted._

## TL;DR

We opted [Formik](https://github.com/jaredpalmer/formik) to build forms in our app, everything was going fine until we had a long dynamically generated form. With as few as ~100 fields, it started to lag a lot. Than I stumbled upon lot of issues Formik has (both open and closed) about speed issues and double renders, so decided to try something else.

[React-final-form](https://github.com/final-form/react-final-form) was next in the list, It turned out to be great choice with a lot of fine grained control options, speed was a lot better, we also enabled `validateOnBlur`, which made it lighting fast. We had to build a few wrappers for [shipify-polaris components](https://polaris.shopify.com/components/get-started) in use. You can find the code/s below.

## Long version

We started building a shopify embedded app with `Rails 6` and `ReactJS`. I was using `react_rails ` gem for the purpose of binding the two.   
**For those of you who don’t know, shopify provides a library of UI components among some guidelines to build shopify plugins/apps keeping the experience as close to original shopify experience as possible**.   
As shopify plugins are rendered in an iframe, that means anyone can use whatever he wants for the UI/backend and pretty much everything. This can result in completely different UI components and their look and feel across different plugins. This is where shopify-polaris comes in to unify the user experience across different plugins.

Shopify provides official react and html versions of this, but their guidelines can be followed independently of the UI framework.

## ENOUGH OF THE SHOPIFY, WHERE ARE FORMS!

OHK! I hear you. Lets get right into forms.

### Building forms with formik

[Formik](https://github.com/jaredpalmer/formik) is a nice small size library, **it is supposed to support all common cases and does not present itself as one stop shop for all kind of form needs**. And they are right. We build small forms with relatively simple [Yup](https://github.com/jquense/yup) validation schema and it was working great. There was no lag or anything like that when editing the form.

Than we had to create a dynamic form which could have N sections, and each section will have minimum of ~35 fields.   
_Building schema for this complex and conditional form was also interesting but that’s not topic here._  
Our normal form had around 100+ fields. When we did our development and testing on sample form of 1 section, everything was working fine. **We used a small helping library [@satel/formik-polaris](https://github.com/SatelCreative/formik-polaris) to bind shopify components and formik without any extra work.**

After everything was built, when we tested this against real world loads of forms with 3-4 sections. It showed huge lag when editing. We would see text changing after a complete second of stopping the key-presses. This was obviously un-acceptable to deliver the feature. Here is when our debugging journey began.

### Trying to fix lags while sticking with formik

As I mentioned earlier, we had a complex schema with conditional logics, array of objects and so on. We knew this is one place where the bottleneck is, formik is validating whole form on a single key-press, but it did not justify this much of the lag.  
**One other issue was multi rendering** , it was re-rendering whole form minimum of 2 times on single key press. Which of-course means a lot of CPU load.

#### Memoization

Initially we suspected it is the re-renders which is causing the main issue, so **we did split our components in smaller chunks with memoization in mind. And used `React.memoize` to make them pure and stop their re-renders.** but despite moving a huge chunk of form to memoized versions, there was little to no effect on lag.

#### Try to reduce re-renders to 1

There were multiple issues which we found during our debugging on formik about multiple re-renders, _with very few ever resolved_, and that either didn’t help us anyway. So we were stuck with multiple re-renders.

**At this point we were so frustrated** with this experience and saw number of open issues about speed on formik’s large forms that we were fully convinced that **formik speed issue is a real thing** , and we need to move forward and try something else. This is when I saw a suggestion on an issue comment in formik to use react-final-form and we thought why not?

### Replacing `formik` with `react-final-form`

React final form’s first impression from [docs](https://final-form.org/react) and readme was that it is built to be one-stop-shop for all kind of forms, which means it has a lot of built in fine grained controls for all kind of use cases. And it is `async` by default. Which means it runs validations async reducing any possibilities of lags due to validations.

`React-final-form` even has [a brief dedicated guide to migrate from formik](https://final-form.org/docs/react-final-form/migration/formik). So i don’t need to add those details. I will only add details which are specific to shopify-polaris.

So as we were using [@satel/formik-polaris](https://github.com/SatelCreative/formik-polaris) which binds polaris components `onChange` and `error` type properties to formik.   
**I could not find anything similar for `react-final-form` which meant i had to write my own wrappers. Which are not a big deal but its always nice to have plug-able solutions instead of writing your own.  
[Here is a gist](https://gist.github.com/ziaulrehman40/f305669431eeb3876671e24ef23f821e)i created with code for the wrappers/adapters and notes on their usage.**

#### Using Yup validation schema with `react-final-form` 

There is apparently no offical way to use a validation schema in `react-final-form` while `formik` had this support. I found a function somewhere in an issue on github. And that worked flawlessly for us, here is the final form of that function we used:

```javascript
import { get, set } from 'lodash-es'
 
// For extracting errors per field for formik
export const convertYupErrorsToFieldErrors = (yupErrors) => {
  return yupErrors.inner.reduce((errors, { path, message }) => {
    if (errors.hasOwnProperty(path)) {
      set(errors, path, get(errors, path) + ' ' + message);
    } else {
      set(errors, path, message);
    }
    return errors;
  }, {});
}
 
 // And to use yup schema for validation:
 export const finalFormYupValidator = async (values, schema) => {
  try {
    await schema.validate(values, { abortEarly: false });
  } catch (errors) {
    return convertYupErrorsToFieldErrors(errors);
  }
}
```

And to use this:

```javascript
import { finalFormYupValidator } from '../../helpers'
 
...
...
 
<Form
      initialValues={initialValues}
      validate={async (values) => await finalFormYupValidator(values, ValidationSchema)}
      onSubmit={async (values) => await submit(values, alert) }
```

Obviously you may tune above according to your needs.

#### Fine tuning `react-final-form` for our usage

As soon as we made switch to `react-final form`, **we saw immediate effect of at-least 4-5x speed improvement** , we could sense a little bit of lag still but it was a lot better already.  
We decided to fix this lag too, so we explored other options. As our form was considerably big, we knew validations are what is causing this remaining lag. So we enabled `validateOnBlur` option(by passing it as a prop to `Form` and voila! Our form was as fast as it could get with no lag at all.