20000 Lieues Sous les Mers

Lition and React.js [DevBlog]

I want to start a series of notes about the Lition front-end. On one side we offer several interesting things in our client app like author’s approach to the organization of unidirectional data flow (UDF) in React.js + Redux, from the other side these kind of things are very simple and are, from my perspective, elegant. Let’s see together.

In this series I’ll try to cover more interesting topics like our UDF, TDD on FE side, Blockchain on FE side, WAI-ARIA, CSS Only and modern Headless Chrome.

Attention! There will be many examples of code that can’t be copied, if it annoys you, then immediately close this note.

About Project

Lition is a global project with distributed team which cover several countries. The front-end team is located in Grodno, Belarus.

https://www.lition.io/team — Technology Team
https://www.lition.io — Expansion

A few words about the project and the idea. Lition is a web trading platform that allows consumers to purchase electricity directly from producers — energy providers. Providers can be either large sellers — public or private power plants, as well as smaller producers which have for example small farms of solar batteries.

The platform provides the consumer with all the necessary information about the producer, including the type of electricity — this is how it was obtained: bio, solar, wind, etc. The purchase of electricity is carried out through the popular blockchain platforms — Ethereum and Hyperledger (not fully, but we are in progress).

The trading platform is unique and very interesting — it is a real revolution in the energy sector. More information about the project can be found on the Lition site — https://www.lition.io.

Recently we have had a business trip to Berlin, to our customer’s head office. The guys exchanged experience and knowledge on the project. At the moment we are trying to erase the boundaries among the front-end, back-end and blockchain teams to get one monolithic agile team which is responsible for supplying the whole product not just some part of it.

I believe that we will succeed!

Client Architecture: React.js + Redux

The entire architecture of our client application is built on a simple concept, which I described in a series of my previous notes (here [eng], here [rus] and here [rus]). The idea already underlies several projects that are at the production stage and are time-tested. We used this concept in different projects, and after that we slightly improved our approach due to our experience.

The only thing left of my “bike” (Archux) in this project is Dispatcher — a tool that solves the problem of side effects. Again, no gadgets such as thunk, saga, rxjs, or anything that we do not need. The main goal is KISS — Keep it simple, stupid. The threshold of input to the code base should be minimal, both for the junior developer and for the senior pro. Everything should look as simple as possible. There is no need to complicate the application if there is no reason.

“…
Simple is better than complex.
Complex is better than complicated.
…”
Zen of Python, June 1999 by Tim Peters

All Actions of the user pass through the Dispatcher. Actions are initiated with the help of performers — Action Performers. State management occurs through Redux, i.e. as I said, my “bike” in the garage. One of the important points why this was done is the various plugins to the browser that work only with Redux. Yes, and psychologically, programmers are easier to accept this approach when they know that there is a popular Redux, and not a “bicycle” of a certain teamlead who suffering from NIH-syndrome.

But the concept itself does not break, the approach will be fair for any library that allows you to work with the state of the data store — Archux, Redux, Flux, Fluxxor …

React-components are divided into 2 types: Containers and Presentational. Containers subscribe to the application Data Store and most often it’s a full web pages of our applications. Presentational components are closer to the implementation of Web Components, these are separate standalone controls or a mapping that does not depend on our application in general. All presentational components are described in the interactive documentation that we deliver with the client application.

Ok, words, words. Talk is cheap. Show me the code, — said Linus Torvalds :) 
So, I show. Consider one cycle of a unidirectional data flow with all it’s steps.

The user agrees with the presentational component — a simple button "Select Producer":

Select Producer Page
File path: /src/components/Button/Button.js

The button placed inside the container component which subscribed to data store using HoC-function connect() of the Redux library.

File path: /src/containers/Producer/Producer.js

On the energy producers page, we have two buttons, one of them allows the end user to select his electricity provider. By the code it is clear that this button calls a certain performer of the action (“performSelectProducer”).

Performer initiates the action through the dispatcher, and also associates this action with the asynchronous service — in the example, this is a request to the server. Below is the code for this action performer:

File path: /src/action_performers/producers.js

An API service that generates HTTP requests through the Axios library:

File path: /src/services/api/producers.js

The code of the dispatcher:

File path: /src/store/dispatcher.js

After a successful external asynchronous operation, the dispatcher sends a response to the data store. The store and the dispatcher are implementations of “Singleton” design pattern, they exist only in one instance.

File path: /src/store/singletonStore.js
File path: /src/store/index.js

Then Redux enters the case — it sends a response to the Reducer.

File path: /src/reducers/producers.js

We do not have the concept of an action with an error, action-successful or action-pending. The user action is one and it has the corresponding name without any silly prefixes or postfixes.

However, the information in action can be a different: an error message; payload data; indicator that the action is asynchronous and it is necessary to wait for an answer; metadata — input arguments — very useful for keeping identifiers.

Container that is subscribed to the data store and to change it’s state, within the corresponding method of component life cycle, responds to the entry in the data store — initiates the appearance of the notification (this is a new round of the unidirectional data flow) and moves to another page — “Overview”.

File path: /src/containers/Producer/Producer.js

Routing and navigation are carried out through the popular library React-Router 4, also we use latest React — 16th version.

File path: /src/containers/Producer/Producer.js

Our routes are configured in the corresponding service. Also there an instance of the route history object was created in the services.

Overview Page. Notification that the producer was changed and the corresponding transaction was saved.
Producer Select (Mobile Layout)
Lition Front-End UDF Diagram

During reading the code, you probably found 2 things:

  1. The container is inherited from some strange class AbstractContainer — it's smelled like Object-Oriented Programming;
  2. And some strange intl property in the context of the container;

I agree, non-obvious things. Let’s talk about this. AbstractContainer is the parent class for all container components. It’s inherited from React.Component. In fact the abstract class is a combination of different mixins that merge common functions: installation of breadcrumbs; preparation of the text structure / labels, according to the selected locale; work with the scroll bar of the page, etc. We used this technique earlier, on our previous projects.

File path: /src/containers/AbstractContainer/AbstractContainer.js

The intl property in the context appears thanks to the provider, responsible for the internationalization (i18n) and localization (l10n) of our application.

At the moment we have two languages (German and English), but the plans for the future is to add a few more.

The solution for localization is not custom, it’s an integration with popular React-Intl library from Yahoo! All translations are stored in the corresponding JSON-files, also we make the necessary settings for the library moment.js— works with the dates and timezones. And for other places where special formatting or conversion is needed we use EcmaScript6 Intl API and in our JS-logic we based on the HTML lang attribute.

File path: /src/providers/LocalizationProvider/LocalizationProvider.js

Locale changing bind to the Data Store. Those everything is done within the scope of the following Action. For a part of the semantics we do not forget in the right places to correctly apply the HTML attribute translate.

File path: /src/components/MetaMaskAlert/MetaMaskAlert.js
Locale / Language Change Control

Thank you for attention and in the next note I’ll try to describe how we develop layout of our app.

P.S. If you have any ideas or thoughts please feel free to share with me.

2018, Artur Basak, Lition Tech Team

Next article: