Improving our React Forms

Kavan Koh
Government Digital Services, Singapore
4 min readJun 22, 2017

Recently, we have been developing a new change request feature for Business Grants Portal, which allowed us to design most areas from the ground up. We use Alt to manage the frontend state of our web application. It was introduced progressively and some page flows were broken down into individual pages. Then came Redux, which was used for the pages around the home page. The framework/libraries used are Ruby on Rails, Slim templates, React Router, Alt, Redux and React.

Ruby on Rails

The show and edit action in the controller displays the form and the summary/submitted page respectively. While 1 action can be used for all 3 pages, displaying the page according to the status of the object would be delegated to the React component. I decided to keep the 2 actions to reduce changes to the existing frontend code.

We use a Slim template to include the root DOM node for rendering React components and some global variables such as the user details and change request object. Where the previous implementation used 2 templates, we used just 1 template by including the variables that both pages needed.

Alternatively, you could use API calls to retrieve data on page loading, which will remove the need to include any variables in the template.

JS

Page Entry, Alt and React Router

We use a page entry to pass the form object, user details and Alt store to the React components. Originally we had separate form and summary stores and this introduced a delay in the page transition. So we merged the separate page entry for the form and summary page, allowing the use of a common react router browser history, resulting in an immediate transition between pages. We removed the summary store since the summary page displays data from the previous page, which is the data from the form store.

Saving and Review

Previously, each section in the form was saved individually when changing sections. For the new change request form, we implemented saving as N simultaneous promises for each section in the form. These are fulfilled before calling more functions to avoid race conditions. The review action follows an almost similar sequence:

  • start the page loading spinner
  • save all sections in the form
  • display a ‘Draft Saved’ message
  • make an asynchronous call to review
  • update the status of the object in the store
  • end the page loading spinner, then display an error message if there are form errors, or route to the summary page
Reviewing an incomplete form. (Network Conditions set at Regular 4G. Left — Form with old setup.)
Reviewing and routing to the summary page. Left— 40 requests, 1.7MB transferred, load time: 6s. Right — 7 requests, 6.9KB transferred, load time: <1s.

User and grant data were fetched for the display of the information box at the top. Scrolling to the top of the window and hiding the review button completed the review.

Right — Submitting the form and displaying an information box at the top.

Edge Cases

Alt and jQuery Growl Messages

As an example, the existing ‘updateSection’ API call is supposed to display a growl message to indicate a draft is being saved but it was displaying multiple ‘Draft saved’ messages due to the multiple sections in the page.

Eventually, I introduced an optional parameter to disable the message and limit the code changes in other files. A good practice is to keep such side effects away from the direct promise that resolves these API calls. They should only do 1 thing — update the Flux store.

Browser Back

On clicking the browser back button, the correct page should be displayed according to the status of the object (e.g. when an object is in summary status, it should not be displayed in the form page). The first option for solving this is to check the status of and trigger a browser forward action at the start of the react component lifecycle. The better solution is to delegate routing according to the object status, to the react router.

Conclusion

We used asynchronous calls to enable the new effects on the pages and remove unnecessary page refreshes. We also reduced code duplication by using a common Slim template, page entry and Alt store.

--

--