Managing state and forms with React, Part 2: Validation
In previous article we discussed how to build basic forms with React, and introduced value link pattern. Now, it’s time to go pro. Difference of the real application is that it needs form inputs validation, which can make your code look like a mess. What I gonna show you now is very different to the most of the React tutorials. I will demonstrate that Value Link pattern is very powerful abstraction, and it will help us to handle forms validation in simple and elegant way.
What exactly is “Form Validation”?
There are several types of things we can do, which might be referred to as “validation”. Their have common purpose — to prevent wrong user input as soon as possible.
- Wrong input rejection. For example, if we have numeric form field, it’s pointless to allow typing letters inside. And since we’re working with React’s controlled form inputs, it means that these letters shouldn’t go to component’s state, so it’s rejection, not validation. <Input /> component itself must know that it works with a number and reject letters.
- Client-side wrong field values indication. Let’s take e-mail field for instance. There’s a regexp pattern valid e-mail must satisfy, but there will be moments of time while user is in the middle of typing and it’s not valid. “vlad@” — is not valid e-mail, but wait, I’m typing. In this situation, you can’t reject wrong input, and have to allow invalid values to appear in the form, while showing some indication of invalid field value. Which means,in turn, that invalid values must go through component state, and state itself needs to be validated.
- Server-side validation. And finally, there are some sorts of checks client just can’t perform alone. What if we’re going to add user with login name, which is already taken? We have to ask the server. It could be done on form’s submit, or it could be done while you’re typing.
In this tutorial, we will concentrate on 2) — instant wrong field values indication while you’re typing. And we will see what it takes to implement it in our “Add user form” example.
So, lets take our simple form component from the previous article. It holds user information in its state, and is supposed to save new user to the server in onSubmit() method, no matter how.
Its render() method uses Volicon ValueLink library, so we have these imports at the module’s top:
And with them, our render() method looks like this:
Quick and Dirty Error Indication
Lets think about some minimal validation we gonna add to our render() method. User name is kinda required, so it should be non-empty. And it shouldn’t contain any spaces.
Email is required and should match email regexp pattern (we took it from stackoverflow, and assigned it to some variable):
And if there are some invalid fields in the form, we would like to disable “Add User” button:
For the beginning, it would be nice to mark our invalid fields with red border. So, if there will be ‘invalid’ class added to them when validation fails, it will be just fine:
This code doesn’t looks bloated yet, but still you can notice some repetitive pattern inside. And when we would like to add error messages near our inputs, it will become much worse:
Okay, now it’s bloated enough. Can we really do something about it?
Validation with Value Links
As usual, an obvious solution would be to hide repetitive patterns inside of custom <Input /> component wrapper. Let it handle how validation error will appear in UI. To do that, we need to tell it about an error somehow. And we wouldn’t like to pass a lot of additional props, because it will eliminate all the benefits.
But we already have wrapper around the value created exactly for the purpose to avoid such problems. It’s value link. So, lets just carry validation error in the link along with a value:
And our markup in render() starts looking really beautiful. As if there wouldn’t be any validation at all:
Great. Now, all we have to do is to assign errors to the links. Fortunately, Volicon’s value link already knows that we gonna do it. So it comes up with a little help:
link.check( whenValid, [ error message ] ) is the method of value link base class, which validates given condition, and when it fails it assigns link.error with its second argument, whatever it is. Plain error message in our case.
But the best thing about link.check is that it could be chained:
Chained link.check() will be evaluated in sequence, and the first check which will fail leaves its error message in the link. Other checks will be omitted.
Which is very helpful, because in real application we would like to show specific error messages which are relevant to the situation. One thing is that field is required, and completely different one is that it has to be valid.
Final solution and design hints
So, that’s how we’re doing simple form validation:
In order to unleash the full power of this approach in real application, you will need to create your own <FormInput /> wrappers. As I shown in previous section, it’s rather trivial. They should encapsulate all repetitive patters you have in your forms, so your forms markup will become semantic and declarative:
- Styles and decorating markup. When you design the form, you should be concentrated on form’s content, not on how to make it look nice.
- Validation error indication, as I just shown above. There are no reason validation should mess up your form’s markup.
- Wrong input rejection for numeric and other fields deserving it.
It’s easy to start, it will really take just one minute:
Now, we got familiar with a value links basics. In the next article we will discuss how to handle the complex nested state. It’s actually the part where the fun starts — with our links we can do a lot of interesting things with just a raw React state. No other “immutable” libraries are required.
Meanwhile, if you like what you see, you can start playing with links. https://github.com/Volicon/valuelink