Skip to content

Instantly share code, notes, and snippets.

@fukajun
Created July 26, 2015 11:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fukajun/83b0d44c003dffef9613 to your computer and use it in GitHub Desktop.
Save fukajun/83b0d44c003dffef9613 to your computer and use it in GitHub Desktop.
flux

Nailing that validation with React JS

Validation is complex. Validation is extremely complex. I think it is right up there at the top of implementations we misjudge regarding complexity. So why is validation so difficult in general? How could we implement this with React JS? And do you get a prize for reading through this article? ... yep, you do! Look forward to a virtual cookie at the bottom of this article, you will definitely deserve it ;-)

At my employer, Gloppen EDB Lag, we are building a React JS component framework for application development. We have everything from grids and panels to calendars and forms. Think of it as React Bootstrap, but with bigger parts specific to our applications. So we have lots of forms in our applications and we needed a form that could handle both user input validation, server validation and be very flexible with the contents of the form.

This article will explain the challenges and the thought process of building such a form component. Forms and validation is complex no matter what framework you use, and even though we look at React JS here, the same principles goes for all frameworks.

As a result of writing this article I built an extension to React JS, formsy-react... and the same concept implemented for Angular JS: formsy-angular. This is a small extension that I think nails that "sweet spot" between flexibility and reuseability of building forms in your application and still get all the difficult wiring of validation for free.

validation in general

Validation is most often related to forms and that is what we are going to focus on here. First of all we have to divide our validation into two:

Client side validation Server side validation You should of course always have server side validation, but to improve user experience we validate on the client side also. Bringing client side validation into forms has seriously made them more complex. It is not just the concept of handling validation state in the form, but we also have many different ways of indicating the actual validation error.

Red border on the input Tooltip Text to the right Text underneath Text on each form element or general text at the top... or bottom Lock submit button until form is valid If that is not enough, we also have a choice of handling validation as we type/blur and not just when submitting the whole form. And even worse, the form should not validate the inputs initially, except if you pass initial values or you have set that input as required.

vaidationのほとんどはフォームに関連している。ここではそのことについてフォーカスして話しをする validationには2種類にわけることができる。

  • クライアントサイド valdation
  • サーバーサイドvalidation

もちろんサーバーサイドのvalidationは常に行うべきであるが、クライアントサイドでもvalidateを おこなうことでUXを高めることができる。 クライアントサイドのvalidationを導入することでより複雑になります。 これは、フォームでの検証状態を処理するだけの概念ではないが、我々は、実際の検証エラーを示す多くの異なる方法があります。

  1. input要素を赤枠にする
  2. ツールチップ
  3. 文章を右に表示する
  4. 文章を下に表示する
  5. 各要素に文章を表示するか、上部または下部に文章を表示する
  6. フォームが有効になるまでsubmitボタンを押せなくする

それで充分でない場合は、フォームのフォーカスがなくなったタイミングやサブミットボタンが押されたタイミングで validdation処理を行うように選択することができます。 そして、さらに悪いことに、フォームに初期値や、入力値を予め設定している場合は、初期のvalidationを行わないべきです。

A scaling related question

A form... is it view state or is it application state? Let me explain that in more detail. View state is handled in the controller of your UI. In Angular JS this would be the controller, in React JS it is the component and in Backbone JS it would be the View. Application state is handled further up in your application architecture. In Angular that would be a service, in React JS (with flux) it is a store and in Backbone JS it would have to be something you made up yourself. So, if nothing else in the application cares about the form we only need to care about view state. If some other part of the application cares about the state of the form, we have to implement application state.

フォームそれは、ビューのstateまたは、アプリケーションのstateでしょうか? このことについて、詳細に説明したいと思います。ビューのstateはコントローラーでハンドリングされます。 Angular JSの場合は、controllerがそれにあたります。React JS では coomponent, Backbone JSでは、Viewにあたります。 アプリケーションの状態をアプリケーショアーキテクチャの中で話を進める。Angular.js serviceがそれにあたり、 React JS(with flux) では、store、そしてBackbone JSでは自分でその役割にあたるものを作る必要がある。 だから、もしアプリケーションの状態を気にする必要がなければビューstateの管理に集中することができます。 もしいくつかのアプリケーションの構成要素が、フォームの状態を気にした場合、アプリケーションの状態を 実装する必要でてきます。

So what is the case? View state or application state? In my experience a form is a completely isolated implementation, which means the only thing that cares about the form is the view (component). In Angular JS and Backbone JS that might not be such a hard choice, as you really do not have a strong concept of application state, but with React JS and FLUX it is a very important question to answer. Jump ahead to "Lets get an overview" if the FLUX part does not interest you.

だからなんなのでしょうか?ビューstateなのかアプリケーションstateなのか?私の経験ではフォームは完全に独立した実装をとなる。つまりフォームが気にするのは、ビュー(Component)であることを意味しています。 もしあなたが、アプリケーションstateに対して強い考えがないのであればAngular JS と Backbone JS では、難しい選択とならないが、React JS with flux では、とても重要な質問への答えとなる。もし、Fluxについて興味がなければ "Lets get an overview" まで読み飛ばして構いません。

React JS FLUX form validation

If you decided that the form was application state you would have to trigger an action to save the form, have a validation state in your store and you would have to grab that state when the request to the server was responded and the store emitted a change. This requires more implementation and most certainly more implementation than you really need. Another thing is that you would still have view state because the user input validation does not have anything to do with the store. Lets visualize just the server validation part:

| FLUX - Application state |

                    |------------|
  |---------------> | DISPATCHER | // 3. Pass submit to store
  |                 |------------|
  |                       |
  |                   |-------|
  |                   | STORE | // 4. Save to server, update state and emit change
  |                   |-------|
  |                       |
  |                 |-----------|
  |                 | COMPONENT | // 1. Get server validation state
  | 2. submit form  |-----------|
  |-----------------------|

This is of course a bigger implementation than:

| FLUX - Component state |

  |-----------|
  | COMPONENT | // Submit, update state based on server response and update component
  |-----------|

So I personally believe validation should be handled within the component, which of course is the simpler, but again least scalable solution. That said you can still notify your stores about the state of the form. You can add success and error handler to your form that triggers an action:

個人的には、validationはcomponentで処理されるべきだと信じている、そのほうがシンプルだからで、やはりスケーラブルである。つまり、成功や失敗をactionとして白化する処理をフォームに追加することによってフォームstateについてStoreに知らせることができます


| FLUX - Application state |

                 |------------|
  |------------> | DISPATCHER | // 3. Pass action to store
  |              |------------|
  |                    |
  |                |-------|
  |                | STORE | // 4. Toggle some state based on success/error
  |                |-------|
  |                    |
  |              |-----------|
  |              | COMPONENT | // 1. Send success/error action on server response when form submitted
  | 2. action    |-----------|
  |--------------------|

So to summarise. An isolated component is the way to go here.

まとめると独立したコンポーネントはそのための方法である

Lets get an overview

Okay, so what we want to do is create a generic form component for our application. The form itself should have a valid/invalid state and its inputs should also have individual valid/invalid states. We also want validation in both directions:

では、自分のアプリケーショのためのcomponentを作っていきましょう。formはvalid/invalidのsteateを持つべきである、またformの各要素であるinput要素もvalid/invalidのstateを持つべきである。それらは双方向に検証可能であるようにしたい。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment