React is a kickass framework built by a bunch of kickass coders at Facebook. It implements a virtual DOM, using a DOM-like approach to instantly add the components you need and instantly remove the ones you don’t. React plays the role of V in the MVC structure, but if you pair it with Flux, you have a kickass framework that easily syncs M and V. More on Flux later~

Components

In React, you can create a component with special functionality that you couldn’t find in HTML elements even if you searched with a lantern, such as the dropdown navigation in this tutorial. Each component has its own territory (scope), so once we define a component, we can reuse it over and over without needing to interact with other components!

Every component has a feature called render, which efficiently returns the HTML to be shot onto the browser. We can also call other React components, which means that once you enter React, it’s as deep as the sea—oh, no, it’s “nothing is impossible, only unimaginable.”

JSX

If you pay close attention to React, you may notice something called JSX. JSX allows us to write HTML in JavaScript instead of using HTML to contain JavaScript. It helps us develop quickly because we don’t have to worry about strings, line breaks, and the like. You can run JSX in the browser, but it’s not recommended because it will slow down your page. Gulp and Grunt provide a JSX interpreter for your preprocessing tasks, so if you want to use JSX, I recommend enabling this feature.

Using JSX

As mentioned earlier, in JSX every component has a render method that produces a “ViewModel” – before returning HTML to the component, you can put the information from this view model into the view, meaning your HTML will dynamically change based on this model (for example, a dynamic list).

Once you’re done, you can return whatever you want to render. Using JSX to do this is so simple.

var ExampleComponent = React.createClass({
    render: function () {
        return (
            <div className="navigation">
                Hello World!
            </div>
            );
    }
});

If you ran this code in your browser, you’d only get a syntax error, because in JavaScript the < and > characters must be enclosed in quotes. When you run the JSX interpreter on the code, it gets transformed into this.

var ExampleComponent = React.createClass({
    render: function () {
        return (
            React.createElement('div', {className: 'navigation'}, 'Hello World!')
            );
    }
});

You can click here to test the example.- I’m using the browser JSX interpreter (not recommended, but for JSFiddle).

It worked! JSX interprets what you generated using React.createElementallDOM nodes, generating node types, parameters, and content. You can go without JSX, but that means you have to manually write all the DOM nodes via React.createElement. Countless examples tell me to use JSX.

You must be wondering why I use className instead of class on the DOM. This is because class is a reserved word in JavaScript. When JSXinterpretsyour code, it changes all the attributes on the node into an object, but you can’t treat the object as an attribute!

Using Variables in Props

If you want to dynamically change a component’s style class (or any other attribute value), you can use variables. However, you can’t just pass in a variable name; you also need to wrap it in a pair of curly braces so JSX knows it’s an external variable.

var ExampleComponent = React.createClass({
render: function () {
    var navigationClass = 'navigation';
    return (
        <div className={ navigationClass }>
            Hello World!
        </div>
        );
}
});

You can see this feature here.

The Initial Renderer

When you first want to render a React component, you need to tell React which component to render and also specify an existing DOM node to indicate where to render that component. To do this, you’ll use the React.render function.

var ExampleComponent = React.createClass({
render: function () {
    return (
        <div className="navigation">
            Hello World!
        </div>
        );
}
});
React.render(<ExampleContent />, document.body);

It will render the component on the body node—simple, right! From then on, you can call other components as usual, or, if you wish, you can use the render function many times, if you don’t want to use React to render the entire page but still want to use multiple components.

The Basics of a Component

Components can have their own “state.” This allows us to reuse the same component many times while making them look completely different, because the state of each component instance is unique.

When you pass properties to a component, these are called props. Don’t limit yourself to HTML attributes; you can pass anything you want and access it inside the component via this.props. This allows us to reuse the same component but pass a different set of props, such as the component’s “configuration.”

Props

Based on our earlier “Hello World!” example, we had the className attribute on the HTML node. Inside the component, we can access this value using this.props.classname, but as mentioned earlier, you can pass anything you like. For our dropdown, we need to configure the navigation as an object, which the component will use as the configuration to render. Let’s get started—

var navigationConfig = [];

var Navigation = React.createClass({
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

If we access this.props.config now, we’ll get an empty array (the value of navigationConfig). Before we get into the actual navigation code, let’s explain state.

State

As discussed earlier, every component has its own “state.” When using state, you first define the initial state, and only then can you use this.setState to update it. Whenever the state is updated, the component calls the render function again, using the new values to replace or change what was previously rendered. This is the essence of the virtual DOM—the diffing algorithm is done inside React, so we don’t have to rely on DOM updates (because the DOM is slow). React computes the differences and produces a set of instructions (for example, adding the “active” class to “navigation__link,” or removing a node), then executes them on the DOM.

For the navigation, we keep the dropdown menu’s open state in the state. To do this, add a getInitialState function to the class configuration object and return an object with the initial state we want.

var navigationConfig = [];

var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

You’ll notice we set it to -1. When we’re about to open a dropdown, we’ll use the position of the navigation item in the configuration array stored in the state, and since array indexes start at 0, we need to use -1 to indicate that no navigation item is currently targeted.

We can access the state using this.state, so if we look at this.state.openDropdown, we should get -1 returned.

Component Lifecycle

Every component has its “lifecycle”—a series of functions you can define in the component’s configuration that will be called over the course of the component’s life. We’ve already seen getinitialstate — it’s called only once, when the component is mounted.

componentWillMount

This function is called when the component is about to be mounted. This means we can run code here that is necessary for the component’s functionality. Since render is called multiple times during the component’s lifecycle, we usually put code that only needs to run once here, such as XHR requests.

var ExampleComponent = React.createClass({
    componentWillMount: function () {
        // xhr request here to get data
    },
    render: function () {
        // this gets called many times in a components life
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

componentDidMount

Once your component has run the render function and actually rendered into the DOM, componentDidMount will be called. Here we can do any DOM operations we need to do, as well as anything that depends on the component actually already existing in the DOM, such as rendering a chart. You can access the DOM node internally by calling this.getDOMNode.

var ExampleComponent = React.createClass({
    componentDidMount: function () {
        var node = this.getDOMNode();
        // render a chart on the DOM node
    },
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

componentWillUnmount

This function will be called when you are about to remove the component from the DOM. This allows us to clean up behind the component, such as removing any event listeners we’ve bound. If wedon’tclean up after ourselves, then when one of those events is triggered, it will try to compute on a component that has not been mounted, and React will throw an error.

var ExampleComponent = React.createClass({
    componentWillUnmount: function () {
        // unbind any event listeners specific to this component
    },
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

Component Methods

React also provides methods for components to make our work easier. They are called during the component’s creation process. For example, getInitialState lets us define a default state, so we don’t have to worry about further checking in the code whether a state item exists.

getDefaultProps

When we create a component, we can define default values for the component’s props as we see fit. This means that when we call the component, if you don’t set values for these props, the component will have a default “configuration,” and we don’t have to worry about checking props in the next line of code.

When you define a component, these default props are cached, so they are the same for every instance of the component and cannot be changed. For the navigation component, we set the configuration to an empty array, so even if no configuration is passed in, no error will occur in the render method.

var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

propTypes

We can also specify a type for each prop as we like. This is very useful for checking and handling unexpected values assigned to props. As in the dropdown below, we specify that only arrays can be put into the configuration.

var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        return (
            <div className="navigation">

            </div>
            );
    }
});

React.render(<Navigation config={ navigationConfig } />, document.body);

mixins

We can also add mixins to components. This is a basic component independent of React (just a configuration of object type). This means that if we have two components with similar functionality, we can share a configuration (if the initial state is the same). We can abstractly create a method in the mixin, so we don't have to write the same code twice.

var ExampleMixin = {
    componentDidMount: function () {
        // bind some event listeners here
    },
    componentWillUnmount: function () {
        // unbind those events here!
    }
};

var ExampleComponent = React.createClass({
    mixins: [ExampleMixin],
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

var AnotherComponent = React.createClass({
    mixins: [ExampleMixin],
    render: function () {
        return (
            <div>
                Hello World!
            </div>
            );
    }
});

This way all components have the same componentDidMount and componentWillUnmount methods, saving us from rewriting code. Anyway, you cannot override these properties; if a property is set in a mixin, it cannot be overridden in this component.

Iteration Loops

When we have an array containing objects, how do we loop through this array and render each object into list items? JSX allows you to use it in any JavaScript file. You can map over the array and return JSX, then use React to render it.

var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website'
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item) {
            return (
                <li className="navigation__item">
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                </li>
                );
        });
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);

Feel free to use navigationConfig in JSFiddle.

The navigation config consists of an array and objects, including an href attribute pointing to a hyperlink and a text attribute for display. When we map, it goes through the array one by one to get objects. We can access href and text and use them in HTML. When returning the list, the list items in this array will all be replaced, so when we put it into React for processing, it will know how to render it!

Mixins

So far, we have achieved the expansion of all dropdown lists. We need to know which item is being dropped down. We will use the .children property to traverse our navigationConfig array. Next, we can loop through the sub-elements of the dropdown.

var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website',
        children: [
            {
                href: 'http://ryanclark.me/how-angularjs-implements-dirty-checking/',
                text: 'Angular Dirty Checking'
            },
            {
                href: 'http://ryanclark.me/getting-started-with-react/',
                text: 'React'
            }
        ]
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item) {
            var children, dropdown;
            if (item.children) {
                children = item.children.map(function (child) {
                    return (
                        <li className="navigation__dropdown__item">
                            <a className="navigation__dropdown__link" href={ child.href }>
                                { child.text }
                            </a>
                        </li>
                    );
                });
                dropdown = (
                    <ul className="navigation__dropdown">
                        { children }
                    </ul>
                );
            }
            return (
                <li className="navigation__item">
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                    { dropdown }
                </li>
                );
        });
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);

Example here- But we can still see the dropdown items, even though we setopenDropdown set it to-1 。

We can access in the componentthis.state, to determine whether the dropdown is opened, and we can add a new CSS style class to it to show the hover effect.

var navigationConfig = [
    {
        href: 'http://ryanclark.me',
        text: 'My Website',
        children: [
            {
                href: 'http://ryanclark.me/how-angularjs-implements-dirty-checking/',
                text: 'Angular Dirty Checking'
            },
            {
                href: 'http://ryanclark.me/getting-started-with-react/',
                text: 'React'
            }
        ]
    }
];
var Navigation = React.createClass({
    getInitialState: function () {
        return {
            openDropdown: -1
        };
    },
    getDefaultProps: function () {
        return {
            config: []
        }
    },
    openDropdown: function (id) {
        this.setState({
            openDropdown: id
        });
    },
    closeDropdown: function () {
        this.setState({
            openDropdown: -1
        });
    },
    propTypes: {
        config: React.PropTypes.array
    },
    render: function () {
        var config = this.props.config;
        var items = config.map(function (item, index) {
            var children, dropdown;
            if (item.children) {
                children = item.children.map(function (child) {
                    return (
                        <li className="navigation__dropdown__item">
                            <a className="navigation__dropdown__link" href={ child.href }>
                                { child.text }
                            </a>
                        </li>
                    );
                });
                var dropdownClass = 'navigation__dropdown';
                if (this.state.openDropdown === index) {
                    dropdownClass += ' navigation__dropdown--open';
                }
                console.log(this.state.openDropdown, index);
                dropdown = (
                    <ul className={ dropdownClass }>
                        { children }
                    </ul>
                );
            }
            return (
                <li className="navigation__item" onMouseOut={ this.closeDropdown } onMouseOver={ this.openDropdown.bind(this, index) }>
                    <a className="navigation__link" href={ item.href }>
                        { item.text }
                    </a>
                    { dropdown }
                </li>
                );
        }, this);
        return (
            <div className="navigation">
                { items }
            </div>
            );
    }
});
React.render(<Navigation config={ navigationConfig } />, document.body);

See the example here– When hovering over "My Website", the dropdown will appear.

Earlier, I added mouse events to each list item. As you can see, I used.bind(bind) call, rather than calling it in other ways – this is because when the user's mouse leaves the element area, we don't need to care where the cursor is; all we need to know is to close the dropdown, so we can set its value to -1. However, we need to know which element is expanded when the user's mouse enters, so we need to know this parameter (the index of the element). We use the binding method to call rather than simply calling through a function because we need to call it through React. If we call it directly, we would need to call it all the time, rather than calling it in the event.

Now we can add many items tonavigationConfig among them, and we can also add styles to the dropdown feature.View example。

Summary

React is a simple, convenient, easy-to-use, and powerful framework. Its concise API allows people to quickly create their own components without dealing with complex DOM or performing some particularly complicated operations, especially when it comes to repeated list items and the like.

Source: http://www.oschina.net/translate/getting-started-with-react