React.js Study Notes

Notes of learning React.js library

Posted by aaronice on December 15, 2015

React.js Study Notes


Introduction to React

React Official Page: https://facebook.github.io/react/

React is a JavaScript library for creating user interfaces by Facebook and Instagram. Many people choose to think of React as the V in MVC.

React is built to solve one problem: building large applications with data that changes over time.

React is all about building reusable components. - React.js

Think in React

Components are Just State Machines

React thinks of UIs as simple state machines. By thinking of a UI as being in various states and rendering those states, it’s easy to keep your UI consistent.

In React, you simply update a component’s state, and then render a new UI based on this new state. React takes care of updating the DOM for you in the most efficient way.

About React.js - Open source, but maintained by Facebook - Can be the “V” (view) in MVC - Ideal for large-scale, single page applications - Uses a high speed virtual DOM - Options to use clean and easy-to-understand JSX syntax

Environment Setup

Actually it’s possible to create a React.js app without installing npm.

By using content delivery network, we can add following snippet to an HTML file to enable React.js:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react-dom.js"></script>

An alternative is to use Babel with Gulp.

Displaying Data

The way we are able to figure this out is that React does not manipulate the DOM unless it needs to. It uses a fast, internal mock DOM to perform diffs and computes the most efficient DOM mutation for you.

React ReactDOM

Why is React So Fast? - Javascript Objects are faster than DOM objects - The React virtual DOM is a Javascript object - React never reads from the “real” DOM - React only writes to the real DOM if needed.


JSX

  • In-browser JSX Transformer
    • It’s great for development, but will take extra time for production code
  • React tools
    • Good for production, pre-process the JSX; e.g. Babel

Rendering Component Tips

It allows maximum of one node to be returned in render function.

The following example will get syntax error:

var Optimistic = React.createClass({
    render: function() {
        return (
            <h1>{this.props.name} loves React</h1>
            <p>React doesnt. Idea: sprinkle some divs here and there.</p>
        );
    }
});

React.render(
    <Optimistic name="Peter" />,
    document.getElementById('myContainer')
);

Render a List of Components

Create a list of React component in an array, and assign it to a wrapper, like <ul></ul>, <div></div>


var TodoItem = React.createClass({
    render: function() {
        return  <li>{this.props.item.text}</li>;
    }
});

var TodoList = React.createClass({
    render: function() {
        var todos = this.props.items.map(function(item) {
            return (
                <TodoItem item={item} />
            );
        });  
        return  <ul>{todos}</ul>;
    }
});


Component Specs and Lifecycle

Component Specifications

  • render()
  • getInitialState()
  • propTypes
  • mixins
  • statics
  • displayName

Lifecycle Methods

  • Mounting: componentWillMount
  • Mounting:componentDidMount
  • Updating: componentWillReceiveProps
  • Updating: shouldComponentUpdate
  • Updating: componentWillUpdate
  • Updating: componentDidUpdate
  • Unmounting: componentWillUnmount

Component Lifecycle

img

Based on Execution sequence of a React component’s lifecycle methods, four scenarios need to be aware of the life­cy­cle meth­ods:

  • Ini­tial Ren­der

  • Props Change

  • State Change

  • Com­po­nent Unmount

The following code snippet con­tains all the life­cy­cle meth­ods and other fre­quenly used method that you can use as start­ing point for cre­at­ing your com­po­nents.

//@jsx React.DOM

var React = require('react'),
    MyReactComponent = React.createClass({

    // The object returned by this method sets the initial value of this.state
    getInitialState: function(){
        return {};
    },

    // The object returned by this method sets the initial value of this.props
    // If a complex object is returned, it is shared among all component instances
    getDefaultProps: function(){
        return {};
    },

    // Returns the jsx markup for a component
    // Inspects this.state and this.props create the markup
    // Should never update this.state or this.props
    render: function(){
        return (<div></div>);
    },

    // An array of objects each of which can augment the lifecycle methods
    mixins: [],

    // Functions that can be invoked on the component without creating instances
    statics: {
        aStaticFunction: function(){}
    },

    // -- Lifecycle Methods --

    // Invoked once before first render
    componentWillMount: function(){
        // Calling setState here does not cause a re-render
    },

    // Invoked once after the first render
    componentDidMount: function(){
        // You now have access to this.getDOMNode()
    },

    // Invoked whenever there is a prop change
    // Called BEFORE render
    componentWillReceiveProps: function(nextProps){
        // Not called for the initial render
        // Previous props can be accessed by this.props
        // Calling setState here does not trigger an an additional re-render
    },

    // Determines if the render method should run in the subsequent step
    // Called BEFORE a render
    // Not called for the initial render
    shouldComponentUpdate: function(nextProps, nextState){
        // If you want the render method to execute in the next step
        // return true, else return false
        return true;
    },

    // Called IMMEDIATELY BEFORE a render
    componentWillUpdate: function(nextProps, nextState){
        // You cannot use this.setState() in this method
    },

    // Called IMMEDIATELY AFTER a render
    componentDidUpdate: function(prevProps, prevState){
    },

    // Called IMMEDIATELY before a component is unmounted
    componentWillUnmount: function(){
    }

});

module.exports = MyReactComponent;


Tips

ReactDOM.render() vs React.render()

From ReactDOM.render and the Top Level React API

When you’re in React’s world you are just building components that fit into other components. Everything is a component. Unfortunately not everything around you is built using React. At the root of your tree you still have to write some plumbing code to connect the outer world into React.

The primary API for rendering into the DOM looks like this:

ReactDOM.render(reactElement, domContainerNode)

To update the properties of an existing component, you call render again with a new element.

If you are rendering React components within a single-page app, you may need to plug into the app’s view lifecycle to ensure your app will invoke unmountComponentAtNode at the appropriate time. React will not automatically clean up a tree. You need to manually call:

ReactDOM.unmountComponentAtNode( domContainerNode )

This is important and often forgotten. Forgetting to call unmountComponentAtNode will cause your app to leak memory.

Difference between state and props in React.js

Some discussion on StackOverflow:

On React.js Official Website:

####A brief interlude: props vs state There are two types of “model” data in React: props and state. It’s important to understand the distinction between the two; skim the official React docs if you aren’t sure what the difference is.

To understand the difference between props and state, we have to know what they are in the first place.

Link to the article

Some helpful extracts from the article:

How State Works

A common way to inform React of a data change is by calling setState(data, callback). This method merges data into this.state and re-renders the component. When the component finishes re-rendering, the optional callback is called. Most of the time you’ll never need to provide a callback since React will take care of keeping your UI up-to-date for you.

What Components Should Have State?

Most of your components should simply take some data from props and render it. However, sometimes you need to respond to user input, a server request or the passage of time. For this you use state.

Try to keep as many of your components as possible stateless. By doing this you’ll isolate the state to its most logical place and minimize redundancy, making it easier to reason about your application.

A common pattern is to create several stateless components that just render data, and have a stateful component above them in the hierarchy that passes its state to its children via props. The stateful component encapsulates all of the interaction logic, while the stateless components take care of rendering data in a declarative way.

What Should Go in State?

State should contain data that a component’s event handlers may change to trigger a UI update. In real apps this data tends to be very small and JSON-serializable. When building a stateful component, think about the minimal possible representation of its state, and only store those properties in this.state. Inside of render() simply compute any other information you need based on this state. You’ll find that thinking about and writing applications in this way tends to lead to the most correct application, since adding redundant or computed values to state means that you need to explicitly keep them in sync rather than rely on React computing them for you.

What Shouldn’t Go in State?

this.state should only contain the minimal amount of data needed to represent your UI’s state. As such, it should not contain:

  • Computed data: Don’t worry about precomputing values based on state — it’s easier to ensure that your UI is consistent if you do all computation within render(). For example, if you have an array of list items in state and you want to render the count as a string, simply render this.state.listItems.length + ' list items' in your render() method rather than storing it on state.
  • React components: Build them in render() based on underlying props and state.
  • Duplicated data from props: Try to use props as the source of truth where possible. One valid use to store props in state is to be able to know its previous values, because props may change as the result of a parent component re-rendering.

Loop and render node (elements) in React.js

Q&A on StackOverflow

Because of Maximum Number of JSX Root Nodes, the return value needs to be wrapped in a container, such as <div></div>

by Dhiraj Bodicherla

render: function() {
  var indents = [];
  for (var i = 0; i < this.props.level; i++) {
    indents.push(<span className='indent'></span>);
  }
  return (
     <div>
      {indents}
      "Some text value"
     </div>
  );
}

Another example for loop in React.js

var rows = [];
for (var i=0; i < numrows; i++) {
    rows.push(<ObjectRow />);
}
return <tbody>{rows}</tbody>;

Conclusion

React.js provides a new way of working with HTML, CSS, and Javascript, the components can be easily re-used, while the virtual DOM concept provides performance improvements on DOM operations. It’s totally fine to write React component working with legacy code, however, it can be hard to manage the data flow and states as the complexity of the project grows. Therefore, a systematic approach, such as an architecture is much needed for a React.js front-end project. In following post, I’ll talk about an architecture, well, it’s not the well-know MVC, in fact, it’s also introduced by Facebook, the Flux.


If you liked this post, you can share it with your followers or follow me on Twitter!