React.js: an interactive tutorial to get started

Realy simple and friendly way to learn React.js framework. Quick, concise and interactive.

Render something

React.renderComponent(
    new React.DOM.div({}, 'something'), 
    document.body
);

This just creates a <div> tag in your body like this:

<body>
    <div>something</div>
</body>

The API is very simple:

  • React.renderComponent(the component, where to render).
  • new React.DOM.div({options: you will see later which ones}, children to add to the div)

You can also use React.DOM.p, React.DOM.span and many more...

Create and render a custom component

var SearchBox = React.createClass({
    render: function(){
        return new React.DOM.input({});
    }
})

React.renderComponent(
    new SearchBox({}), 
    document.body
);

This creates the following html:

<body>
    <input/>
</body>

In this case the React.createClass will return a Class. The render method is required and is called when the SearchBox component is actually added on screen. The return value from the render method should be a React js component instance.

You can return the class without the new keyword, but in order to keep is consistent we use the new keyword in this tutorial.

Create a compund component

var SearchBox = React.createClass({
    render: function(){
        return React.DOM.div({},
            new React.DOM.p({}, 'Search box'), 
            new React.DOM.input({})
        );
    }
});

React.renderComponent(
    new SearchBox({}), 
    document.body
);

This creates the following html:

<body>
    <p>Search box</p>
    <input/>
</body>

The only new thing is the render method that renders a <div> with <a> and <p> tags into it. Notice that we have added the React.DOM.p and React.DOM.input into the React.DOM.div. You can pass as many arguments as you want after the first one (which are the options) and are added as children.

API:

  • React.DOM.*(options, child 1, child 2, ..., child n);

Passing props

var SearchBox = React.createClass({
    render: function(){
        return React.DOM.div({},
            new React.DOM.p({
            }, 'Search box'), 
            new React.DOM.input({
                placeholder: this.props.defaultText
            })
        );
    }
});

React.renderComponent(
    new SearchBox({
        placeholder: 'my text'
    }), 
    document.body
);

The props are just input data to send to the component. This data doesn't change in the component that received them.

You just have to look at the placeholder: 'my text' where placeholder is a random name for a prop. This will send the object {placeholder: 'my text} to the SearchBox component. Now inside the SearchBox you will have the this.props object which in this case is the same as the object passed ({placeholder: 'my text}). So you can get the value by just doing this this.props.placeholder.

Using state

var SearchBox = React.createClass({
    getInitialState: function(){
        return {
            value: 'Pro JavaScript'
        }
    },

    render: function(){
        return React.DOM.div({},
            new React.DOM.p({
            }, 'Search box'), 
            new React.DOM.input({
                placeholder: this.props.defaultText,
                value: this.state.value
            })
        );
    }
});

React.renderComponent(
    new SearchBox({
        defaultText: 'my text'
    }), 
    document.body
);

Here you can notice we added the getInitialState function that returns a simple object with a key value. This method is called before the component is mounted/added on screen.

Then we retrive the state value in the render method value: this.state.initialValue.

Now the component has a default value in the text box.

Should I put states or props?

You should always try to have as less state as possible. So first of all try to use it as a prop, if is not possible use it as state. You can check the React.js explanation here.

Events: listen on the change event

Change the input value and an alert will be shown.

var SearchBox = React.createClass({
    getInitialState: function(){
        return {
            value: 'Pro JavaScript'
        }
    },

    render: function(){
        return React.DOM.div({},
            new React.DOM.p({
            }, 'Search box'), 
            new React.DOM.input({
                placeholder: this.props.defaultText,
                value: this.state.value,
                onChange: this.props.onChange
            })
        );
    }
});

React.renderComponent(
    new SearchBox({
        defaultText: 'my text',
        onChange: function(e){
            alert(e.target.value);
        }
    }), 
    document.body
);

Here we just added the onChange: this.props.onChange listener on the React.DOM.input. What exactly it does? First of all let's see where it comes the this.props.onChange. This comes from the constructor:

new SearchBox({
    defaultText: 'my text',
    onChange: function(e){
        alert(e.target.value);
    }
}),

So the this.props.onChange is just this function. This function is then passed to the React.DOM.input:

new React.DOM.input({
    placeholder: this.props.defaultText,
    value: this.state.value,
    onChange: this.props.onChange
})

This is a prop from the React.js library which is called when the input value changes.

When the value is changed is called this code:

onChange: function(e){
    alert(e.target.value);
}

This just receives an argument e which is a syntetic event and then we get the target of the event, which is a HTMLInputElement that has been created with the React.DOM.input. From this we can easily get the value and show it to the user.

Check here all the events supported.

Communicate between components

Try to change the input and the text below will be updated. Ups! The text input never change value :/ Let's see the code:

var SearchBox = React.createClass({
    getInitialState: function(){
        return {
            value: 'Pro JavaScript'
        }
    },

    render: function(){
        return React.DOM.div({},
            new React.DOM.p({
            }, 'Search box'), 
            new React.DOM.input({
                placeholder: this.props.defaultText,
                value: this.state.value,
                onChange: this.props.onChange
            })
        );
    }
});

var globalValue = '';

var render = function(){
    React.renderComponent(
        new React.DOM.div({},
            new SearchBox({
                defaultText: 'my text',
                onChange: function(e){
                    globalValue = e.target.value;
                    render();
                }
            }), 
            new React.DOM.p({}, globalValue)                      
        ),
        document.body
    );
}

render();

What changed?

Now the renderComponent function method receives a React.DOM.div which contains the SearchBox and a new element React.DOM.p. Now instead of showing an alert with the value, we store it into the globalValue variable. Notice that the newly created React.DOM.p receives the globalValue as a child.

But this doesn't work!

When the input value changes, the render() method (which has also been introduced in this new version) is called and re-renders the user interface, so the value of the React.DOM.input's state is still the same so it doesn't change. In order to fix this problem we have to change the state. These are the changes:

onInputChange: function(e){
    this.setState({value: e.target.value});
    this.props.onChange(e);                
},

render: function(){
    return React.DOM.div({},
        new React.DOM.p({
        }, 'Search box'), 
        new React.DOM.input({
            placeholder: this.props.defaultText,
            value: this.state.value,
            onChange: this.onInputChange
        })
    );
}

And this is the result:

Now try to change the input and works as expected!

How to use refs

Refs are like a reference to the node. In this way you don't get the reference of the node by the event (from the e variable in the event callback) but you can get it directly from the this.refs.myNode.

Let's see the new updated code:

var SearchBox = React.createClass({
    getInitialState: function(){
        return {
            value: 'Pro JavaScript'
        }
    },

    onInputChange: function(e){
        this.setState({value: this.refs.input.value});
        this.props.onChange(e);                
    },

    render: function(){
        return React.DOM.div({},
            new React.DOM.p({
            }, 'Search box'), 
            new React.DOM.input({
                ref: 'input',
                placeholder: this.props.defaultText,
                value: this.state.value,
                onChange: this.onInputChange
            })
        );
    }
});

var globalValue = '';

var render = function(){
    React.renderComponent(
        new React.DOM.div({},
            new SearchBox({
                defaultText: 'my text',
                onChange: function(e){
                    globalValue = e.target.value;
                    render();
                }
            }), 
            new React.DOM.p({}, globalValue)                      
        ),
        document.body
    );
}

render();

Notice the differencs:

new React.DOM.input({
    ref: 'input',
    placeholder: this.props.defaultText,
    value: this.state.value,
    onChange: this.onInputChange
})

At line #2 we have ref: 'input' which will store that specific React.DOM.input into the this.refs.input.

Then in the event callback we make this change:

onInputChange: function(e){
    this.setState({value: this.refs.input.value});
    this.props.onChange(e);                
},

The important line is this.refs.input.value which gets the value of the input. Compare it to the previous one e.target.value.

Which one is better? Well, it depends by the use, but the event based is better when you need it into the event callback. The ref way is better when you get the reference to the node from another place. And you can also use both versions.

Thanks for learning React.js, if you enjoyed you may also retweet below, to make your friends know about this amazing framework.

Further reading

I'm really passionate aboute React.js therefore you can find many posts on my blog, I will list some of them here:

Subscribe to receive new interesting posts about programming

comments powered by Disqus