React memo with Formik

Viewed 3402

I have an application with a lot of form fields. I want an approach by which I can avoid re-rendering. I am using Formik to manage the forms.

I am using Formik's useField to access the Formik form value in my child component as React.memo only does a shallow comparison. I want to write a custom callback for the memo method

function MainForm3() {
  const initialValues = { txtArea: "" };
  return (
    <Formik initialValues={initialValues}>
      {(formik) => {
        return (
          <>
            <TextArea
              name={"txtArea"}
              rows={3}
              id={"txtArea"}
              label={"txtArea"}
            />
          </>
        );
      }}
    </Formik>
  );
}

function TextArea(props: any) {
  const [field] = useField(props);

  return <TextField {...field} />;
}

React.memo(TextArea, (prev, next) => {
  //how do i get access to the formik to perform a comparison
});

As the prev and next value have only access to the direct properties that are passed I am not able to compare the Formik field values in the memo function.

To get a handler to the Formik field i need to use a useField, but that does not work in the callback as it says Hooks cannot be used in a non React method.

As i have a complex form i need to have a handler to perform an actual deep comparison before allowing the render.

I don't want to use Fastfield as its internal comparison is just the same shallow.

I am using React 16.13 and Formik 2.1.5

1 Answers

Formik uses React context under the hood. This creates a problem with extra rerenders. Have a look at the article.
In your scenario simply adding memoization will not work, all the components nested into <Formik> will be rerendered whenever Formik's values change.Instead you can try using withFormik hoc, it does not use react context under the hood so adding React.memo will work. 

I had to deal with the same problem few days ago and I found out that useFormik, useField, useFormikContext causes all nested components to rerender, so just avoid using these hooks. If you need to use onChange, onBlur, setFieldValue, errors or touched - pass them as props to your inputs.

Related