Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering Formik Field outside Formik form

We have our own input components (like Checkbox, Textbox, or even CurrencyInput component)

We are now using Formik. So we replaced all <input... with <Field... in our components, eg.

const Checkbox = (props) => {
  ...
  return (
    <div className={myClass1}>
      <Field type='checkbox' name={props.name} className={myClass2} ... />
      <label ...>{props.label}</label>
    </div>
  )
};

Now the problem is, we can't have a standalone Checkbox outside a form anymore (eg. for an on-screen-only option). It will throw:

this.props.formik.registerField is not a function

We feel this is a dealbreaker. But before we ditch Formik and write our own form validation logics, I wonder if anyone else are having this dependency issue.

Is there really no way of rendering Formik Field outside Formik?

like image 503
Aximili Avatar asked Jan 02 '23 03:01

Aximili


1 Answers

The Field component is what connects a form field to the Formik state. It uses context under the hood; Formik is the context provider and Field is the context consumer. Field is tied to Formik and has no use outside of it. For your use case where you want to render form fields that are sometimes connected to Formik and sometimes not, I would export two different components:

  1. The base Checkbox component that has nothing to do with Formik. It should just use a normal input
  2. A Field wrapper around that Checkbox component

While the Field component can take a type, causing it to render the corresponding input, it can also take a render prop to render whatever you want, and it is passed all of the state Formik manages for that field.

For example, your Checkbox and CheckboxField components could looks something like this:

const Checkbox = (props) => {
  ...
  return (
    <div className={myClass1}>
      <input type='checkbox' checked={props.checked} onChange={props.onChange} />
      <label ...>{props.label}</label>
    </div>
  )
};

const CheckboxField = (props) => {
  return (
    <Field name={props.name}>
      {(field) => <Checkbox label={props.label} {...field} />}
    </Field>
  )
}

Now you use have two components that render exactly the same, but one is meant to be used within a Formik form (CheckboxField) and the other can be used anywhere (Checkbox).

like image 175
TLadd Avatar answered Jan 08 '23 01:01

TLadd