Declarative Form Rules
How can I update field B when field A changes from X to Y?
The users of 🏁 React Final Form continue to suggest interesting use cases that challenge just what is possible from a form library, and stimulate my imagination about possible solutions.
Today’s problem was:
How can I update field B when field A changes from X to Y?
As the API stands currently, this could not be accomplished with
🏁 Final Form Calculate, as it matters what the
previous value was. We need a way to run some code to update another field
when one field changes, without calling the update in render()
.
This requires a stateful component to subscribe to changes to a field and
keep track of what the previous value was. It was pretty trivial to code up an
OnChange
component that doesn’t render anything, but calls a callback when the
field value changes. This seemed so potentially useful that I went ahead and,
for completeness, created OnBlur
and OnFocus
, resulting in the library
🏁 React Final Form Listeners.
Having just discovered this idea, I have not yet decided how useful it is, or whether or not it’s a good idea, but I’m sharing it to get feedback from others. These components allow us to write “form rules” as non-rendering components, like this:
<WhenFieldChangesfield="pickup"becomes={true}set="delivery.street"to={undefined}/>
How do we write WhenFieldChanges
? Well, we need a Field
to get the
onChange
function for the field we want to change, and then the OnChange
component to notify us when the field we want to listen to has changed value.
const WhenFieldChanges = ({ field, becomes, set, to }) => (<Field name={set} subscription={{}}>{(// No subscription. We only use Field to get to the change function{ input: { onChange } }) => (<OnChange name={field}>{(value) => {if (value === becomes) {onChange(to);}}}</OnChange>)}</Field>);
It’s important to notice that the function given to OnChange
will only be
called when the value changes, not on every render. Let’s see how it looks in
practice.
Conclusion
I’m still not convinced how useful this concept is, but it’s kind of fun to explore the boundaries of what React allows us to do. Component composition, and letting them keep state as the data cascades through them, is extremely powerful.
As always, feedback welcome and encouraged! 🤔