Quantcast
Channel: 懒得折腾
Viewing all articles
Browse latest Browse all 764

The React.js Way

$
0
0

The React.js Way: Getting Started Tutorial

Update: the second part is out! Learn more about the React.js Way in the second part of the series: Flux Architecture with Immutable.js.

Now that the popularity of React.js is growing blazing fast and lots of interesting stuff are coming, my friends and colleagues started asking me more about how they can start with React and how they should think in the React way.

React.js Tutorial Google Trends(Google search trends for React in programming category, Initial public release: v0.3.0, May 29, 2013)

However, React is not a framework; there are concepts, libraries and principles that turn it into a fast, compact and beautiful way to program your app on the client and server side as well.

In this three-part blog series React.js tutorial I am going to explain these concepts and give a recommendation on what to use and how. We will cover ideas and technologies like:

  • ES6 React
  • virtual DOM
  • Component-driven development
  • Immutability
  • Top-down rendering
  • Rendering path and optimization
  • Common tools/libs for bundling, ES6, request making, debugging, routing, etc.
  • Isomorphic React

And yes we will write code. I would like to make it as practical as possible.
All the snippets and post related code are available in the RisingStack GitHub repository .

This article is the first from those three. Let’s jump in!

Repository:
https://github.com/risingstack/react-way-getting-started

1. Getting Started with the React.js Tutorial

If you are already familiar with React and you understand the basics, like the concept of virtual DOM and thinking in components, then this React.js tutorial is probably not for you. We will discuss intermediate topics in the upcoming parts of this serie. It will be fun, I recommend you to check back later.

Is React a framework?

In a nutshell: no, it’s not.
Then what the hell is it and why everybody is so keen to start using it?

React is the “View” in the application, a fast one. It also provides different ways to organize your templates and gets you think in components. In a React application, you should break down your site, page or feature into smaller pieces of components. It means that your site will be built by the combination of different components. These components are also built on the top of other components and so on. When a problem becomes challenging, you can break it down into smaller ones and solve it there. You can also reuse it somewhere else later. Think of it like the bricks of Lego. We will discuss component-driven development more deeply in this article later.

React also has this virtual DOM thing, what makes the rendering super fast but still keeps it easily understandable and controllable at the same time. You can combine this with the idea of components and have the power of top-down rendering. We will cover this topic in the second article.

Ok I admit, I still didn’t answer the question. We have components and fast rendering – but why is it a game changer? Because React is mainly a concept and a library just secondly.
There are already several libraries following these ideas – doing it faster or slower – but slightly different. Like every programming concept, React has it’s own solutions, tools and libraries turning it into an ecosystem. In this ecosystem, you have to pick your own tools and build your own ~framework. I know it sounds scary but believe me, you already know most of these tools, we will just connect them to each other and later you will be very surprised how easy it is. For example for dependencies we won’t use any magic, rather Node’s require and npm. For the pub-sub, we will use Node’s EventEmitter and as so on.

(Facebook announced Relay their framework for React at the React.js Conf in January 2015. But it’s not available yet. The date of the first public release is unknown.)

Are you excited already? Let’s dig in!

The Virtual DOM concept in a nutshell

To track down model changes and apply them on the DOM (alias rendering) we have to be aware of two important things:

  1. when data has changed,
  2. which DOM element(s) to be updated.

For the change detection (1) React uses an observer model instead of dirty checking(continuous model checking for changes). That’s why it doesn’t have to calculate what is changed, it knows immediately. It reduces the calculations and make the app smoother. But the really cool idea here is how it manages the DOM manipulations:

For the DOM changing challenge (2) React builds the tree representation of the DOM in the memory and calculates which DOM element should change. DOM manipulation is heavy, and we would like to keep it at the minimum. Luckily, React tries to keep as much DOM elements untouched as possible. Given the less DOM manipulation can be calculated faster based on the object representation, the costs of the DOM changes are reduced nicely.

Since React’s diffing algorithm uses the tree representation of the DOM and re-calculates all subtrees when its’ parent got modified (marked as dirty), you should be aware of your model changes, because the whole subtree will be re-rendered then.
Don’t be sad, later we will optimize this behavior together. (spoiler: with shouldComponentUpdate() and ImmutableJS)

React.js Tutorial React re-render(source: React’s diffing algorithmChristopher Chedeau)

How to render on the server too?

Given the fact, that this kind of DOM representation uses fake DOM, it’s possible to render the HTML output on the server side as well (without JSDom, PhantomJS etc.). React is also smart enough to recognize that the markup is already there (from the server) and will add only the event handlers on the client side. This will be very useful in the third article where we will write an isomorphic application with React.

Interesting: React’s rendered HTML markup contains data-reactid attributes, which helps React tracking DOM nodes.

Useful links, other virtual DOM libraries

Component-driven development

It was one of the most difficult parts for me to pick up when I was learning React.
In the component-driven development, you won’t see the whole site in one template.
In the beginning you will probably think that it sucks. But I’m pretty sure that later you will recognize the power of thinking in smaller pieces and work with less responsibility. It makes things easier to understand, to maintain and to cover with tests.

How should I imagine it?

Check out the picture below. This is a possible component breakdown of a feature/site. Each of the bordered areas with different colors represents a single type of component. According to this, you have the following component hierarchy:

  • FilterableProductTable

What should a component contain?

First of all it’s wise to follow the single responsibility principle and ideally, design your components to be responsible for only one thing. When you start to feel you are not doing it right anymore with your component, you should consider breaking it down into smaller ones.

Since we are talking about component hierarchy, your components will use other components as well. But let’s see the code of a simple component in ES5:

var HelloComponent = React.createClass({
    render: function() {
        return <div>Hello {this.props.name}</div>;
    }
});

But from now on, we will use ES6. ;)
Let’s check out the same component in ES6:

class HelloComponent extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

JS, JSX

As you can see, our component is a mix of JS and HTML codes. Wait, what? HTML in my JavaScript? Yes, probably you think it’s strange, but the idea here is to have everything in one place. Remember, single responsibility. It makes a component extremely flexible and reusable.

In React, it’s possible to write your component in pure JS like:

  render () {
    return React.createElement("div", null, "Hello ",
        this.props.name);
  }

But I think it’s not very comfortable to write your HTML in this way. Luckily we can write it in a JSX syntax (JavaScript extension) which let us write HTML inline:

  render () {
    return <div>Hello {this.props.name}</div>;
  }

What is JSX?
JSX is a XML-like syntax extension to ECMAScript. JSX and HTML syntax are similar but it’s different at some point. For example the HTML class attribute is called className in JSX. For more differences and gathering deeper knowledge check out Facebook’s HTML Tags vs. React Components guide.

Because JSX is not supported in browsers by default (maybe someday) we have to compile it to JS. I’ll write about how to use JSX in the Setup section later. (by the way Babel can also transpile JSX to JS).

Useful links about JSX:
JSX in depth
Online JSX compiler
Babel: How to use the react transformer.

What else can we add?

Each component can have an internal state, some logic, event handlers (for example: button clicks, form input changes) and it can also have inline style. Basically everything what is needed for proper displaying.

You can see a {this.props.name} at the code snippet. It means we can pass properties to our components when we are building our component hierarchy. Like: <MyComponent name="John Doe" />
It makes the component reusable and makes it possible to pass our application state from the root component to the child components down, through the whole application, always just the necessary part of the data.

Check this simple React app snippet below:

class UserName extends React.Component {
  render() {
    return <div>name: {this.props.name}</div>;
  }
}

class User extends React.Component {
  render() {
    return <div>
        <h1>City: {this.props.user.city}</h1>
        <UserName name={this.props.user.name} />
      </div>;
  }
}

var user = { name: 'John', city: 'San Francisco' };
React.render(<User user={user} />, mountNode);

Useful links for building components:
Thinking in React

React loves ES6

ES6 is here and there is no better place for trying it out than your new shiny React project.

React wasn’t born with ES6 syntax, the support came this year January, in version v0.13.0.

However the scope of this article is not to explain ES6 deeply; we will use some features from it, like classes, arrows, consts and modules. For example, we will inherit our components from theReact.Component class.

Given ES6 is supported partly by browsers, we will write our code in ES6 but transpile it to ES5 later and make it work with every modern browser even without ES6 support.
To achieve this, we will use the Babel transpiler. It has a nice compact intro about the supported ES6 features, I recommend to check it out: Learn ES6

Useful links about ES6
Babel: Learn ES6
React ES6 announcement

Bundling with Webpack and Babel

I mentioned earlier that we will involve tools you are already familiar with and build our application from the combination of those. The first tool what might be well known is the Node.js‘s module system and it’s package manager, npm. We will write our code in the “node style” and require everything what we need. React is available as a single npm package.
This way our component will look like this:

// would be in ES5: var React = require('react/addons');
import React from 'react/addons';

class MyComponent extends React.Component { ... }

// would be in ES5: module.exports = MyComponent;
export default MyComponent;

We are going to use other npm packages as well.
Most npm packages make sense on the client side as well,
for example we will use debug for debugging and superagent for composing requests.

Now we have a dependency system by Node (accurately ES6) and we have a solution for almost everything by npm. What’s next? We should pick our favorite libraries for our problems and bundle them up in the client as a single codebase. To achieve this, we need a solution for making them run in the browser.

This is the point where we should pick a bundler. One of the most popular solutions today areBrowserify and Webpack projects. Now we are going to use Webpack, because my experience is that Webpack is more preferred by the React community. However, I’m pretty sure that you can do the same with Browserify as well.

How does it work?

Webpack bundles our code and the required packages into the output file(s) for the browser. Since we are using JSX and ES6 which we would like to transpile to ES5 JS, we have to place the JSX and ES6 to ES5 transpiler into this flow as well. Actually, Babel can do the both for us. Let’s just use that!

We can do that easily because Webpack is configuration-oriented

What do we need for this? First we need to install the necessary modules (starts with npm initif you don’t have the package.json file yet).

Run the following commands in your terminal (Node.js or IO.js and npm is necessary for this step):

npm install --save-dev webpack
npm install --save-dev babel
npm install --save-dev babel-loader

After we created the webpack.config.js file for Webpack (It’s ES5, we don’t have the ES6 transpiler in the webpack configuration file):

var path = require('path');

module.exports = {
  entry: path.resolve(__dirname, '../src/client/scripts/client.js'),
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'bundle.js'
  },

  module: {
    loaders: [
      {
        test: /src\/.+.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      }
    ]
  }
};

If we did it right, our application starts at ./src/scripts/client/client.js and goes to the ./dist/bundle.js for the command webpack.

After that, you can just include the bundle.js script into your index.html and it should work:
<script src="bundle.js"></script>

(Hint: you can serve your site with node-static install the module with, npm install -g node-static and start with static . to serve your folder’s content on the address: 127.0.0.1:8080.)

Project setup

Now we have installed and configured Webpack and Babel properly.
As in every project, we need a project structure.

Folder structure

I prefer to follow the project structure below:

config/
    app.js
    webpack.js (js config over json -> flexible)
src/
  app/ (the React app: runs on server and client too)
    components/
      __tests__ (Jest test folder)
      AppRoot.jsx
      Cart.jsx
      Item.jsx
    index.js (just to export app)
    app.js
  client/  (only browser: attach app to DOM)
    styles/
    scripts/
      client.js
    index.html
  server/
    index.js
    server.js
.gitignore
.jshintrc
package.json
README.md

The idea behind this structure is to separate the React app from the client and server code. Since our React app can run on both client and server side (=isomorphic app, we will dive deep into this in an upcoming blog post).

How to test my React app

When we are moving to a new technology, one of the most important questions should be testability. Without a good test coverage, you are playing with fire.

Ok, but which testing framework to use?
My experience is that testing a front end solution always works best with the test framework by the same creators. According to this I started to test my React apps with Jest. Jest is a test framework by Facebook and has many great features that I won’t cover in this article.

I think it’s more important to talk about the way of testing a React app. Luckily the single responsibility forces our components to do only one thing, so we should test only that thing. Pass the properties to our component, trigger the possible events and check the rendered output. Sounds easy, because it is.

For more practical example, I recommend checking out the Jest React.js tutorial.

Test JSX and ES6 files

To test our ES6 syntax and JSX files, we should transform them for Jest. Jest has a config variable where you can define a preprocessor (scriptPreprocessor) for that.
First we should create the preprocessor and after that pass the path to it for Jest. You can find a working example for a Babel Jest preprocessor in our repository.

Jet’s also has an example for React ES6 testing.

(The Jest config goes to the package json.)

Takeaway

In this article, we examined together why React is fast and scalable but how different its approach is. We went through how React handles the rendering and what the component-driven development is and how should you set up and organize your project. These are the very basics.

In the upcoming “The React way” articles we are going to dig deeper.

I still believe that the best way to learn a new programming approach is to start develop and write code.
That’s why I would like to ask you to write something awesome and also spend some time to check out the offical React website, especially the guides section. Excellent resource, the Facebook developers, and the React community did an awesome job with it.

Next up

If you liked this article, subscribe to our newsletter. The remaining part of the The React waypost series are coming soon. We will cover interesting topics like:

  • immutability
  • top-down rendering
  • Flux
  • isomorphic way (common app on client and server)

See you soon and check out the repository until that!
https://github.com/RisingStack/react-way-getting-started

The React.js Way: Flux Architecture with Immutable.js

This article is the second part of the “The React.js Way” blog series. If you are not familiar with the basics, I strongly recommend you to read the first article: The React.js Way: Getting Started Tutorial.

In the previous article, we discussed the concept of the virtual DOM and how to think in the component way. Now it’s time to combine them into an application and figure out how these components should communicate with each other.

Components as functions

The really cool thing in a single component is that you can think about it like a function in JavaScript. When you call a function with parameters, it returns a value. Something similar happens with a React.js component: you pass properties, and it returns with the rendered DOM. If you pass different data, you will get different responses. This makes them extremely reusable and handy to combine them into an application. This idea comes from functional programming that is not in the scope of this article. If you are interested, I highly recommend reading Mikael Brevik’s Functional UI and Components as Higher Order Functions blog post to have a deeper understanding on the topic.

Top-down rendering

Ok it’s cool, we can combine our components easily to form an app, but it doesn’t make any sense without data. We discussed last time that with React.js your app’s structure is a hierarchy that has a root node where you can pass the data as a parameter, and see how your app responds to it through the components. You pass the data at the top, and it goes down from component to component: this is called top-down rendering.

React.js component hierarchy

It’s great that we pass the data at the top, and it goes down via component’s properties, but how can we notify the component at a higher level in the hierarchy if something should change? For example, when the user pressed a button?
We need something that stores the actual state of our application, something that we can notify if the state should change. The new state should be passed to the root node, and the top-down rendering should be kicked in again to generate (re-render) the new output (DOM) of our application. This is where Flux comes into the picture.

Flux architecture

You may have already heard about Flux architecture and the concept of it.
I’m not going to give a very detailed overview about Flux in this article; I’ve already done it earlier in the Flux inspired libraries with React post.

Application architecture for building user interfaces – Facebook flux

A quick reminder: Flux is a unidirectional data flow concept where you have a Store which contains the actual state of your application as pure data. It can emit events when it’s changed and let your application’s components know what should be re-rendered. It also has a Dispatcher which is a centralized hub and creates a bridge between your app and the Store. It has actions that you can call from your app, and it emits events for the Store. The Store is subscribed for those events and change its internal state when it’s necessary. Easy, right? ;)

Flux arhitecture

PureRenderMixin

Where are we with our current application? We have a data store that contains the actual state. We can communicate with this store and pass data to our app that responds for the incoming state with the rendered DOM. It’s really cool, but sounds like lot’s of rendering: (it is). Remember component hierarchy and top-down rendering – everything responds to the new data.

I mentioned earlier that virtual DOM optimizes the DOM manipulations nicely, but it doesn’t mean that we shouldn’t help it and minimize its workload. For this, we have to tell the component that it should be re-rendered for the incoming properties or not, based on the new and the current properties. In the React.js lifecycle you can do this with the shouldComponentUpdate.

React.js luckily has a mixin called PureRenderMixin which compares the new incoming properties with the previous one and stops rendering when it’s the same. It uses the shouldComponentUpdate method internally.
That’s nice, but PureRenderMixin can’t compare objects properly. It checks reference equality(===) which will be false for different objects with the same data:

boolean shouldComponentUpdate(object nextProps, object nextState)

If shouldComponentUpdate returns false, then render() will be skipped until the next state change.(In addition, componentWillUpdate and componentDidUpdate will not be called.)

var a = { foo: 'bar' };
var b = { foo: 'bar' };

a === b; // false

The problem here is that the components will be re-rendered for the same data if we pass it as a new object (because of the different object reference). But it also not gonna fly if we change the original Object because:

var a = { foo: 'bar' };
var b = a;
b.foo = 'baz';
a === b; // true

Sure it won’t be hard to write a mixin that does deep object comparisons instead of reference checking, but React.js calls shouldComponentUpdate frequently and deep checking is expensive: you should avoid it.

I recommend to check out the advanced Performance with React.js article by Facebook.

Immutability

The problem starts escalating quickly if our application state is a single, big, nested object like our Flux store.
We would like to keep the object reference the same when it doesn’t change and have a new object when it is. This is exactly what Immutable.js does.

Immutable data cannot be changed once created, leading to much simpler application development, no defensive copying, and enabling advanced memoization and change detection techniques with simple logic.

Check the following code snippet:

var stateV1 = Immutable.fromJS({
  users: [
    { name: 'Foo' },
    { name: 'Bar' }
  ]
});

var stateV2 = stateV1.updateIn(['users', 1], function () {
  return Immutable.fromJS({
    name: 'Barbar'
  });
});

stateV1 === stateV2; // false
stateV1.getIn(['users', 0]) === stateV2.getIn(['users', 0]); // true
stateV1.getIn(['users', 1]) === stateV2.getIn(['users', 1]); // false

As you can see we can use === to compare our objects by reference, which means that we have a super fast way for object comparison, and it’s compatible with React’s PureRenderMixin. According to this we should write our entire application with Immutable.js. Our Flux Store should be an immutable object, and we pass immutable data as properties to our applications.

Now let’s go back to the previous code snippet for a second and imagine that our application component hierarchy looks like this:

User state

You can see that only the red ones will be re-rendered after the change of the state because the others have the same reference as before. It means the root component and one of the users will be re-rendered.

With immutability, we optimized the rendering path and supercharged our app. With virtual DOM, it makes the “React.js way” to a blazing fast application architecture.

Learn more about how persistent immutable data structures work and watch the Immutable Data and React talk from the React.js Conf 2015.

Check out the example repository with a ES6, flux architecture, and immutable.js:
https://github.com/RisingStack/react-way-immutable-flux



Viewing all articles
Browse latest Browse all 764

Trending Articles