Beliebte Suchanfragen
|
//

Road testing React.js

19.1.2016 | 10 minutes of reading time

React.js is a JavaScript library which is getting increasing attention at conferences , on social media and not least among codecentric developers. I heard about this library some time ago, but I used to treat it as a niche topic and just another JavaScript thingy. But I think now is the perfect time to dive deeper into React.js.

For me the most interesting question is: What are the circumstances in which my project needs the help of React.js? For me this question comprises the following:

  • What is the problem React.js helps me solve?
  • How mature is this library?
  • How large is the community?
  • How useful is the available documentation?
  • Does React.js guide me to maintainable and testable code?
  • How easy is it to integrate it in existing applications and how well can I integrate third party artefacts?
  • What tools can I use for my daily work with React.js?

At the end of this article I hope that you’ll get a better understanding of what React.js really is about and when it is appropriate for you to apply to your project.

To make things a little more approachable, I have built a little example application with which I’d like to explain some of the concepts.
This application can be found here: http://soccerreact.herokuapp.com/ and the sources can be found at GitHub: https://github.com/holgergp/soccerReact

With the application you can manage a soccer league table, which perhaps reminds you of a well known German soccer magazine:

You can drag and drop teams around, edit your team names (useful at the beginning of a new season) and the table shows if the teams perhaps qualify for some international tournaments, or are in trouble qualifying for the next season.
We don’t look at persistence within this article, I think this would be too much for this kind of read. But we do store our data locally in the browser’s local storage, which we will see later.
But let’s dive right in.

How mature is React.js?

React.js was brought to life in 2013 by Facebook (applying a BSD license). The library is actually in use at Facebook, but other big players are using it as well. Given this, we can assume some kind of production readiness. But only looking at the backing of a large company might be misleading as the vague strategy moving from AngularJS 1.x to AngularJS 2.x showed recently.

Which problem does React.js help me solve?

Similar to AngularJS, React.js can be described as a client side JavaScript library.
But this comparison does not tell the whole story: AngularJS helps implement a MVC-structured application (whether this is a good thing or not won’t be discussed here ;)) React.js “only” supports you with the “V” (view)-part of your application.
But you can enhance your React.js application using the so called FLUX architecture: This architectural style describes how “components” communicate (solely) unidirectional with “actions” and “stores”. But we won’t tackle any more details of FLUX here, as it would go beyond the scope of this article.

But where are the difference in the view-layer that React.js introduces?
One of the main design goals of the React.js developers was to avoid having multiple places in an application where you alter state. Two-way databinding is seen as an example of that. In a large application it might be difficult to spot the origin of state mutation.
A React.js-based application forces you to only have a single point of state storage and mutation (or at least very few points). You are then able to process the content of this state in an immutable manner, wherever your application sees fit.
React.js is said to be doing things fast, especially in comparison to AngularJS, and doing well processing large datasets. That is because all state mutations are handled by a “virtual” DOM implementation. “Virtual DOM” means changes are not propagated to the underlying DOM directly. The difference of two state-changes is detected efficiently and only the result of this diff is sent to the DOM. But as a developer you won’t touch those details.

Furthermore React.js applications are solely composed from “components”. The React.js term component refers to application parts that are independent. To get there React.js applies a hierarchical approach. Within that hierarchy our state is often is located at the root of this component tree. Thus it is advisable to first structure your application on paper before you start hacking. On paper you identify functional areas (components) and dataflow. We will see later on in our example application how this can work.

Another thing that might catch your eye is JSX. JSX is an extension of JavaScript that allows using markup as a first-level citizen within your scripts. So it’s quite easy for you to define components and refer to them. This may look like this:

1render: function () {
2    return (
3      <div>
4        <SampleComponent myProperty={this.state.myProperty}/>
5        <SampleForm onConcertSubmit={this.handleConcertSubmit}/>
6      </div>
7    );
8  }

You can use plain JavaScript, but the syntax lacks elegance in comparison:

1React.createElement(
2       "div",
3       null,
4       React.createElement(SampleComponent, { myProperty: this.state.myProperty }),
5       React.createElement(SampleForm, { onConcertSubmit: this.handleConcertSubmit })
6);

But it works just as fine. The downside of the JSX approach is that you need a transpiler.

What about community and documentation?

The community is getting larger every hour, or at least it feels so. To get a feel, here are some numbers in comparison:

React.jsAngularJSKnockout.js
Questions on stackoverflow.com678313166314840
Github stars30681439676900
Google hits695.00012.600.000558.000

I’d conclude two things from these numbers:

  • AngularJS is still mainstream today
  • React.js is already relevant today

I think the documentation part of React.js is quite good, especially in comparison to other frameworks and libraries. It provides good starting points but goes into depth where needed. Thumbs up!
However, the quality of the AngularJS docs, especially when looking at topics dealing with testing, is not yet there.

The sample application

Now I’d like to shift our focus to the sample application:
Scaffolding for our application is nicely done with a Yeoman-Generator (https://github.com/newtriks/generator-react-webpack ).
First thing to do is to break down the app in its components. The result is a rather simple, but helpful structure, as you can see in the picture:

This structure is directly reflected in code:
Looking at src/components, you’ll find these artefacts:

  • App.js
  • LeagueTable.js
  • Position.js
  • Team.js

that have a direct reference to the picture. Additionally there’s run.js, which starts the application and one artefact for constants.

We are managing the state of our application in one place (as outlined above). That one place is the LeagueTable. The most eye-catching function of a react-component is its render-function. This function is called whenever React.js detects a change and wants to rerender that component reflecting the new state.
In the LeagueTable we define the basic template of our HTML structure and some callbacks for our application logic. We will look at the callbacks in a second.
The basic structure looks like this:

1var positionNodes = this.state.positions.map(function (posIter) {
2      return (
3        <Position position={posIter} key={posIter.position}/>
4      );
5    });
6 
7return (
8 <div className="col-md-6">
9   <div className="panel panel-primary">
10     <div className="panel-heading">
11       <h3 className="panel-title">Ligatabelle</h3>
12     </div>
13     <div className="panel-body">
14       {positionNodes}
15     </div>
16   </div>
17 </div>
18);

Looks familiar, doesn’t it? But it may be a little odd that we mix markup and JavaScript. I grew to like it quite fast though. 🙂
Two things are interesting at this stage:
First we are building a – tag, which refers to the positions component (which we imported in the file above ).
Second we see here that we are working on the .state property of the component (as opposed to the components further down the tree).
The following components are much simpler in their core.
Taking a glimpse at the positions -component and its render-function, we see this:

1render: function () {
2    const position = this.props.position;
3    const team = this.props.position.team;
4    return (
5      <div>
6        <span>
7         <Team team={team} positionNumber={position.position} />
8      </span>
9      </div>
10    );
11  }

We do not access the state of our application here (and in the child components), but we use the .props-property. Those are immutable properties. Thus we only have one place where we manage our state. The team looks similar in its static structure.
But let’s take a look at the application logic:

The first thing I tackled was DragAndDrop: Here the distinction between team and position is starting to make sense. The positions remain static, only the mapping between a team and a position changes while dragging and dropping.
To implement DragAndDrop I used react-dnd . I won’t go into the details of DragAndDrop here. Only this much: The positions form the DropTarget and the DragSource are the teams.
Interesting here is: At the end of a drag we call a callback, which we have defined in the LeagueTable and have passed down (as a prop). This callback then is the central point where we resort our table.

The second point I implemented was editing of the teams names. I used react-wysiwyg to implement this. This is a simple wrapped around HTML5-Content-Editable.
The pattern here looks similar. In the Team-component we define the markup .

1<ContentEditable
2 tagName='div'
3 onChange={onChange}
4 className='textPointer'
5 html={team.name}
6 autofocus={true}
7 maxLength={200}
8 editing={this.props.team.editing}
9 preventStyling
10 noLinebreaks
11 />

The callback is again defined in the LeagueTable .

The third interesting thing is LocalStorage. The LeagueTable -component is responsible for this as well. We use additional functions of a react-component:
getInitialState and componentDidUpdate.

getInitialState defines the starting state of a component. Here I check if LocalStorage is present in the browser and if matching data is present in the LocalStorage.
Then I load those stored values or I load some predefined defaults.
componentDidUpdate is called whenever components did change. Here I store the current state to the LocalStorage.

To better track the different stages of the sourcecode, I supplied different git branches for every implementation step. Starting with a version without dynamics and ending with the full version containing DragAndDrop .

How maintainable is the resulting code and what about (unit) tests?

To test the application I used Jasmine and I have written some sample unit tests for the LeagueTable -component. I did not notice that many peculiarities. Test arrangement is a bit uncommon, the concept of virtual rendering may confuse a little bit. But you get good support by React-Utilities. So to answer the question: Can you unit test React.js applications? Yes!

Due to the fact that React.js encourages the developer to slice the application in components and to hold state only in few places, the application is designed to be maintainable.
What may be problematic is that the state-holding component (here the LeagueTable) may be a little overloaded with callbacks and logic. Applying the FLUX architecture, you can address this problem quite elegantly.

What I like during development is the well helpful error messages and logs. JSX may be a little uncommon (“Why another language variant?”), but I think this makes semantics more clear, and I like it.

It did take me some time to get my head around the React way of thinking, but the decisions are reasonable and I like the result.

Integration

As shown in the example, it is not that difficult to use third party libs to build more sophisticated functionality in order to tackle more complex requirements. The integration into existing applications is possible as well: As an example you can look at ngReact . But this may be evaluated on a per-case basis.

Tooling

The toolchain that is used here is similar to other JavaScript stacks. The use of a transpiler like Babel might feel a little unfamiliar in some cases. But you can still fall back to plain JavaScript (ES5).
I developed the application using IntelliJ and I was supported quite well. I can recommend it.

When does it make sense to add React.js to my stack?

React.js might not be suitable in every case where you want to use client-side logic or SPAs.
The investment in the toolchain and in the way of thinking might still be too far away from the mainstream.
But I can think of at least two scenarios where React.js shines:

  • If you build self-contained widgets (such as a LeagueTable)
  • If the application has to handle and view large datasets and performance is your concern

Further on it is advisable to look at FLUX in this context, to build larger applications using React.js.
Have fun playing around with React.js!

|

share post

//

More articles in this subject area

Discover exciting further topics and let the codecentric world inspire you.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.