React form validation with MobX

Nick Kozhukharenko
4 min readNov 1, 2016

--

Handling an input from a user and validating it — it’s feature that is present in every SPA.

As usual, fortunately (or unfortunately — choose what you like more), in React community there is no conventional approach of doing this. For those who are using Redux, there are permanent leader — redux-forms. But what to do if you are using MobX? We should search for the most suitable library on the vast Github or invent a wheel.

I come across the mobx-react-form library. But after browsing a docs and a source code (it’s quite big, thought), I found out that it has too many features what I don’t need.

For now I need only next features:

  1. Show Error under each filed if it isn’t valid (give to user an instant feedback)
  2. Disable a submit button if a form is not valid.

The implementation should fit the next criteria:

  1. reduce repetition in form components
  2. be simple and clear (less than 30 lines of code)
  3. use the full power of MobX
  4. easy to scale

As an example, we will do a validation for login form and then will try to extract a logic to a generic class. While a form isn’t filled correctly — a button is disabled.

Form input component

Following a component-driven development approach let’s implement a stateless form-input component. The usage should look like this:

The implementation:

This component is totally ‘controlled’ which means that

  • the value is set with the props. The FormInput component can receive value and error. If the error is passed — it’s shown beneath input.
  • the form data is updated through an onFieldChange() handler. This callback is called each time with ‘field-name’ and ‘value’ arguments.

Login form model

Second step — defining form model.

Pay attention to the form data is decorated by MobX@bservable decorator.

To handle a validation itself we will use a ValidatorJS library. I choose it over several others for its declarativeness, small size and multilingual support.

The next important piece of the FormStore class is the onFieldChange() function. It should validate and update model by settings a new value to such fields as value, error and isValid.

Notice that each field was extended with one more field — rule which will be consumed by a Validator.

onFieldChange() is the function that is to be called whenever the text in any of the form fields changes.

It calls theValidator and then updates the model — this.form

Then let’s create LoginForm — the form component for login with two inputs — one for email and another for a password. It will receive an observable form data and the onFieldChange callback.

We got a static ‘dump’ component

And we can use it the next:

Actually, we can even pass a whole instance of LoginStore to the LoginForm.

Extracting common logic

To make this login reusable we can extract onFieldChange()s to a separate class and then all other classes will inherit from it.

getFlattenedValues() turns

{
fields: {
email: {value: ‘val’}
}
}

into

{ email: 'val }

We can call setError() action to set a generic form error.

It’s useful if we want to display some async error, e.g.

post('http://localhost:300')
.then(() => /* your code*/ )
catch((e) => form.setError(e.message))

FormStore usage:

Conclusion

In this tutorial I explained how to handle React forms validation and keep it as simple as possible using MobX.

It’s scalable: you can add more methods to superclass — the FormStore, if needed, and override/add custom ones to the subclasses. And this solution is pretty simple, isn’t it?

What is next?

For now, it’s my approach to form validation of React components.

Features to consider:

  • Show validation errors only when the user stopped typings (onBlur).
  • Delay validation errors until the user submits the form.

So, in future I’ll extend a superclass with more functionality — so there might be a part II. Let me know if you are interested in it.

Full working example can be found here:

Additional resources to read:

--

--