v5.0.0
๐ v5.0.0 โ HOOKS!!! ๐
First to explain why this change was made... To manage subscriptions to the internal ๐ Final Form instance, ๐ React Final Form has been using some legacy lifecycle methods that make the side effect of subscribing to an event emitter cumbersome. Such subscriptions are a perfect use case (no pun intended) for the new React.useEffect()
hook. In an effort to modernize and future proof the library, the entire thing has been rewritten to use hooks.
All the previous tests have been rewritten to use ๐ React Testing Library, which is a superior way to test React components. None of the tests were removed, so all existing functionality from v4
should work in v5
, including some optimizations to minimize superfluous additional renders that were made possible by hooks.
โ ๏ธ BREAKING CHANGES ๐ฎ
Don't worry...there really aren't that many.
- Requires
^react@16.8.0
. That's where the hooks are. ๐ - All deprecated functions provided in
FormRenderProps
andFormSpyRenderProps
have been removed. They have been spitting warnings at you sincev3
, so you've probably already corrected for this. The following applies to:batch
blur
change
focus
initialize
mutators
reset
Rather than spreading the FormApi
into the render props, you are just given form
itself.
v4
<Form onSubmit={submit}>{({ reset }) => (
// fields here
<button type="button" onClick={reset}>Reset</button>
)}</Form>
v5
<Form onSubmit={submit}>{({ form }) => (
// fields here
<button type="button" onClick={form.reset}>Reset</button>
)}</Form>
Field
will no longer rerender when thevalidate
prop. Note: it will still always run the latest validation function you have given it, but it won't rerender when the prop is!==
. This is to allow the very common practice of providing an inline=>
function as a field-level validation function. This change will break the very rare edge case where if you are swapping field-level validation functions with different behaviors on subsequent renders, the field will no longer rerender with the new validation errors. The fix for this is to also change thekey
prop onField
any time you swap thevalidate
function. See this test for an example of what I mean. There's also a sandbox demonstrating the issue:
- The previously exported
withReactFinalForm
HOC has been removed. Now you should use theuseForm()
hook if you'd like to get the ๐ Final Form instance out of the context. To ease your transition, you can make your own with a single line of code:
const withReactFinalForm = Component => props =>
<Component reactFinalForm={useForm()} {...props} />
๐ New Hook API ๐
Because it was so easy to do, ๐ React Final Form now exports the useField
and useFormState
hooks that are used internally in Field
and FormSpy
respectively. Literally the only thing Field
and FormSpy
do now is call their hook and then figure out if you are trying to render with the component
, render
, or children
prop.
For example, before v5
, if you wanted to create a custom error component that only rerendered when touched
or error
changed for a field, you'd have to do this:
v4
const Error = ({ name }) => (
<Field name={name} subscription={{ touched: true, error: true }}>
{field =>
field.meta.touched && field.meta.error ? (
<span>{field.meta.error}</span>
) : null
}
</Field>
)
...but now you can do:
v5
const Error = ({ name }) => {
const field = useField(name, { subscription: { touched: true, error: true } })
return field.meta.touched && field.meta.error ? (
<span>{field.meta.error}</span>
) : null
}
Not too groundbreakingly different, but these hooks might allow for some composability that was previously harder to do, like this clever disgusting hack to listen to multiple fields at once.
Go forth and hook all the things! ๐ฃ
Special thanks to @Andarist for giving me such an extensive code review on #467.