Last time I wrote about React features I think are nice, today I am gonna show a small example of the components and what I’ve done with it last week.

In the example I will build a list of bookmarks.


/** @jsx React.DOM */
var Link = React.createClass({
    getInitialState: function() {
        return {}; //Here you could put initial data state
    },
    deleteObj: function() {
        this.props.onDelete(this.props.key);
    },
    render: function() {
        return (
            <div ref="item"
                 className="row link-block well">
                <div className="col-md-11">
                    <div>
                        <a href={this.props.url} className="link-title"
                           ref="title">
                            {this.props.title}
                        </a>
                    </div>
                </div>
                <div className="col-md-1">
                    <div>
                        <a href="#delete" onClick={this.deleteObj}>
                            <span className="glyphicon glyphicon-remove delete-obj"></span>
                        </a>
                    </div>
                </div>
            </div>
        )
    }
});

This would be the Link element, It is an object in our list of links. It has a delete method, but nothing more complex.

The props object and the state object are well explained in the React tutorial.

In the render function we have the template for the Link object and we could add events, (onClick, onSubmit), React calls them Synthetic Events.

After this we will need an object to get the list of links.


var LinkList = React.createClass({
    render: function() {
        var onDelete = this.props.onDelete;

        var links = this.props.data.map(function(link) {
            var tags = link.tags.map(function(tag) {
                return <Tag slug={tag.slug} name={tag.name}
                			key={tag.id}
                            />;
            });

            return <Link url={link.url} title={link.title} key={link.id}
                         tags={tags} pub_date={link.pub_date}
                         onDelete={onDelete}
                         />;
        });

        return (
            <div className="link-list">
                {links}
            </div>
        )
    }
});

Here we iterate through the links and we create Link objects, once we have all of them, we just pass links to render and It will take care of their HTML.

As you might have seen, we have a Tag object we didn’t define here yet, links have tags so we could filter them easily, this would be an example of the Tag object.


var Tag = React.createClass({
    render: function() {
        var hash = '#' + this.props.slug;

        return (
            <a href={hash} className="tag small">
                {this.props.name}
            </a>
        )
    }
});

We would need a form to add new bookmarks too.


var LinkForm = React.createClass({
    componentDidMount: function() {
        $('input[name="tags"]').tagsinput(); //Here I am using the jquery tagsinput plugin
        //This gets triggered after React mounts the content in the DOM
    },
    addObj: function() {
        var url = this.refs.url.getDOMNode().value.trim();
        this.props.onSubmit(url);
    },

    render: function() {
        return (
            <div className="link-add">
                <div>
                    <input type="text" ref="url" />
                    <input type="text" name="title" ref="title" />
                    <input type="text" name="tags" ref="tags" />
                    <input type="button" onClick={this.addObj} value="add" />
                </div>
            </div>
        )

Once we click add, we trigger an event and execute a function not yet defined, It’s because we will pass this function from the parent, so we could control the data flow and the list of elements from there.

The parent would look something like this.


var LinkBox = React.createClass({
    handleAddLink: function(url) {
        link = {url: url};

        $.ajax({
            type: 'POST',
            url: this.props.url,
            data: link,
            headers: {'X-CSRFToken': $.cookie('csrftoken')},
            success: function(data) {
                var links = this.state.data;
                //I do this so the new added link will be on top of the array
                var newLinks = [data].concat(links);
                this.setState({data: newLinks});
            }.bind(this)
        });
    },
    deleteObj: function(data_id) {
        var links = this.state.data;
        var newlinks = links.filter(function(elem) {
            return elem.id != data_id;
        });

        this.setState({data: newlinks});

        $.ajax({
            type: 'DELETE',
            url: '/api/links/' + data_id + '/',
            success: function() {
                //...
            }.bind(this),
            headers: {'X-CSRFToken': $.cookie('csrftoken')}
        });
    },
    loadLinksFromServer: function() {
        $.ajax({
            url: this.props.url,
            dataType: 'json',
            success: function(data) {
              this.setState({data: data});
            }.bind(this)
        });
    },
    getInitialState: function() {
        return {data: []};
    },
    componentWillMount: function() {
        this.loadLinksFromServer();
    },
    render: function() {
        return (
            <div>
                <h3>Links</h3>

                <LinkForm url={this.props.url} onSubmit={this.handleAddLink} />

                <LinkList data={this.state.data}
                           onDelete={this.deleteObj}
                />
            </div>
        )
    }
});

In the parent element we will load the data and we control the actions for the objects.

We can move the AJAX calls to another object, but I didn’t do it for the example.

The way we load data in React is very easy to make it real time, there are some examples out there.


React.renderComponent(
  <LinkBox url={'/api/links/'}/>,
  document.getElementById('content')
);

Where content is the id in our template where we load everything.