jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.92k stars 2.78k forks source link

Confusing error when using `render` prop with hooks #1770

Open erikdstock opened 5 years ago

erikdstock commented 5 years ago

📖 Documentation

The <Formik /> component takes both a component prop and a render prop for its inner form, and in some cases these two may be interchangeable.

const InnerForm: React.FC<FormikProps<FormValues>> = props => {
  const whatever = useSomeHook('ok')
  return <form {...etc} />
}

// Later ...
<Formik
  initialValues={v}
  validationSchema={s}
  render={InnerForm}    /* A */
  render={p => <InnerForm {...p} />}  /* B */
  component={InnerForm} /* C */
/>

These three forms all might function identically in some cases, but if InnerForm is using a hook A above will raise an Uncaught Invariant Violation: Hooks can only be called inside the body of a function component. It's a confusing message since I clearly passed a FC in all cases. B will be fine, since the InnerForm is still being created in the context of a function. This issue also affects a FC passed as children, ie `{InnerForm}.

I understand that some of these might not be common patterns, but when you hit it it's pretty confusing.

Thats it and thanks! Happy to try to submit a docs update but won't be able to get to it in the short term.

johnrom commented 5 years ago

The docs are pretty clear on what is accepted here, so I don't think there is really anything to do. The render prop almost always a render function and not a component, according to React's own docs: https://reactjs.org/docs/render-props.html

Our docs match: https://jaredpalmer.com/formik/docs/next/api/formik#render-props-formikprops-values-reactnode

I generally use a child function instead of a render prop, if that is at all helpful, and just pretend the render prop doesn't exist.

https://jaredpalmer.com/formik/docs/next/api/formik#children-reactreactnode-props-formikprops-values-reactnode

We could clarify the warning if render prop passes a component, but I don't think any docs changes are necessary.