๐ Final Form โ Field Arrays and Mutators
Extending the core functionality of Final Form
After the release of ๐ Final Form and ๐ React Final Form seven days ago, the very first feature that people asked for was array fields / arrays of fields. I could have pretty easily implemented the ability to push, pop, insert, etc. into array values as part of ๐ Final Form, but the reason that Redux Form got so gargantuan was from exactly this sort of feature bloat, where many individuals added on their own pet feature, and everyone that uses the library has to download all of these features whether they use them or not. How could I avoid this with ๐ Final Form?
๐ Final Form is already more or less feature complete (famous last words) as far as editing flat or arbitrarily deep form values. But how could it be made more extensible? Well, hereโs what I came up with:
Mutators
Mutators are functions that can be provided to ๐ Final Form that are allowed to
mutate any part of the form state. You provide an object of mutators when you
call createForm()
, and then they are exposed (bound to the form state) on the
form instance you get back, under form.mutators.whatever()
. A mutator function
is given: the arguments it was called with, the form state, and a collection of
utility functions, like getIn
and setIn
to read and mutate arbitrarily deep
values, as well as changeValue
, which updates a field value in the form state.
They can mutate the state however they wish, and then the form and field
subscribers that need to be notified will be notified.
What does this look like? Well, hereโs a somewhat simplistic example that I created when writing the unit tests:
/** Clears a form value */const clear = ([name], state, { changeValue }) => {changeValue(state, name, () => undefined)}/** Converts a form value to uppercase **/const upper = ([name], state, { changeValue }) => {changeValue(state, name, value => value && value.toUpperCase())}const form = createForm({onSubmit,mutators: { clear, upper }})...form.mutators.upper('foo')...form.mutators.clear('foo')
These are dumb examples, but what else does this allow? Well, for one, it allowsโฆ..
Field Arrays
Everyone doesnโt need to include the code for field arrays in their bundle, but for those that doโฆ..
Introducing:
๐ Final Form Arrays
This library (687 bytes gzipped) contains mutators for performing array operations on form values in ๐ Final Form.
import { createForm } from "final-form";import arrayMutators from "final-form-arrays";// Create Formconst form = createForm({mutators: {// potentially other mutators here...arrayMutators,},onSubmit,});// pushform.mutators.push("customers", { firstName: "", lastName: "" });// popconst customer = form.mutators.pop("customers");
And of course it needs a companion:
๐ React Final Form Arrays
This library
(1.7 kB gzipped)
consists of a <FieldArray/>
component that very closely mimics the
functionality of
Redux Form's <FieldArray/>
component,
providing a fields object that is very array-like, with methods like forEach
,
map
, push
, pop
, shift
, splice
, etc. When you iterate through it, it
gives you the array-syntax strings (e.g. foo[0]
) for the array value in your
form, ready to be used with the <Field/>
component.
An example is worth 1,024 wordsโฆ
Going Forward
I have some other ideas of functionality that can be provided by mutators, and Iโm sure you do, too. They could provide some very powerful features to your forms in the future, without imposing feature bloat on applications that just need a simple login and account form.
As always, feedback welcome! Thanks for reading. โค๏ธ