There are a lot of form libraries for react out there that promise the on true, right way to do things. Two years into my own ReactJS journey, and I’ve come to a few conclusions.
Form State Does Not Belong in a Store
Think of how your browser usually works, does it send form data anywhere before a save button or whatever is clicked or a request made? Not usually.
Things that put form state into a store (like redux or mobx) feel wrong to me. Instead, that state belongs in the component themselves. Nothing else really needs to know about form data until it needs to be sent somewhere. Just like the browser’s default, ReactJS based forms should keep their state contained to the component encapsulating the form.
Don’t Use a Library
I have a hard time with coupling a third party library (aside from react itself) with my code. Instead, I’d recommend writing a simple, higher-order component to take care of the most boilerplate filled parts of react forms: the state change and props stuff.
// really fast example, pulled and simplified from an application import React, { Component } from 'react'; function form(Wrapped) { return class Form extends Component { constructor(props) { this.state = { data: {}, } } bind(name) { return { name, value: this.state.data[name] || '', onChange: e => this.set(name, e), }; } set(name, value) { // could handle functions or use an updater function here // updater functions haven't been really performant for me // in forms, but I haven't dug deeply into that. this.setState({ data: { ...this.state.model, [name]: value, }, }); } render() { return React.createElement(Wrapped, { ...this.props, form: { data: this.state.data, bind: this.bind, set: this.set, }, }); } } }
The above will probably take care of about 80% of the react form headaches without pulling in an dealing with yet another third party dependency. And, more importantly, the form component can grow as the application itself grows. Need new features? Add them as necessary.
The usage of the above looks something like this.
function SomeForm({ form }) { return ( <form> <input type="text" {...form.bind('someInput')} /> <input type="text" {...form.bind('otherInput')} /> </form> ); } const WrappedSomeForm = form(SomeForm);
Libraries like redux are minimally invasive. Application component do not care where they get props from and Redux’s higher-order component makes it so those component don’t have to care.
A form library, however, can go anywhere from minimally invasive — like the above HOC — to maximally invasive where there are requirements to wrap things or use only the form library specific components.
I’ve gone both routes now (custom stuff and libraries) and can tell you that custom form code has grown a lot better as the application has grown.