erikras.com
HomeAbout

Declarative Form Rules

How can I update field B when field A changes from X to Y?

Posted in Coding, 🏁 Final Form
March 22, 2018 - 3 min read
Declarative Form Rules

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:

<WhenFieldChanges
field="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! 🤔

Discuss on Twitter

© 2023 Erik Rasmussen