This is super basic, but I think the concepts here might help someone just starting out with React (as I am).

In this example, I'm going to create a very basic (nigh unusable, but a good basis for understanding, I hope) tabbed navigation UI that changes out a set of elements to simulate changing pages.

To start out, we'll create an <App /> element to hold all of our stuff.

Next, let's create a component to hold the tabbed navigation.

  var Tabs = React.createClass({
    render: function(){
        return (
            <nav>
                <ul></ul>
            </nav>
        )
    }
});

And another component for each individual tab.

  var Tab = React.createClass({
    render: function(){
        return (
            <li></li>
        )
    }
});

In order to populate our tabs, let's create an array.

  var tabList = [
    { 'id': 1, 'name': 'Mike', 'url': '/mike' },
    { 'id': 2, 'name': 'Donnie', 'url': '/donnie' },
    { 'id': 3, 'name': 'Raph', 'url': '/raph' },
    { 'id': 4, 'name': 'Leo', 'url': '/leo' }
];

Next, we'll tie all these pieces together and hook them into our <App />.

We've added some kind of weird syntax and some plain JavaScript to hook things together.

A couple of things to note:

  • The whole this.props thing. When you create a component, you can pass data into it. That data is accessed through its props. If you want the props to change over time, you'll change it via its state. We'll get to that later.
  • We're looping over all the tabs in the array using plain a JavaScript .map. Look, you're learning JavaScript concepts just 'cause that's the vibe of React. I think that's pretty cool.

We'll continue our little exercise by changing things on the page when we click on each of the tabs.

Let's add a click event.

  var Tab = React.createClass({
    handleClick: function(e){
        e.preventDefault();
        this.props.handleClick();
    },

    render: function(){
        return (
            <li>
                <a onClick={this.handleClick} href={this.props.url}>
                    {this.props.name}
                </a>
            </li>
        );
    }
});

We're giving our <Tab /> a handleClick method which, in turn, calls another handleClick method one level up in the <Tabs /> component.

  var Tabs = React.createClass({
    handleClick: function(){
        this.props.changeTab(tab);
    },

    render: function(){
        return (
            <nav>
                <ul>
                    {this.props.tabList.map(function(tab) {
                        return (
                            <Tab
                                key={tab.id}
                                handleClick={this.handleClick.bind(this, tab)}
                                url={tab.url}
                                name={tab.name}
                            />
                        );
                    }.bind(this)}
                </ul>
            </nav>
        );
    }
});

Things get a little verbose here. The handleClick method in this component calls a changeTab method yet another level up in the <App /> component.

The key property (and the corresponding ids in the tabList array) is to keep React happy. It puts a message in the console complaining if it's not here.

I'm a little iffy about why the .bind business needs to be there. Someone want explain it to me?

Now we bring it all home in the <App /> and get to the method that will (soon!) actually do what we set out to do.

  var App = React.createClass({
    changeTab: function() {
        console.log('I am going to change the tab soon.');
    },

    render: function(){
        return(
            <div>
                <Tabs changeTab={this.changeTab} tabList={tabList} />
            </div>
        );
    }
});

To actually get things to change when a tab is clicked, we'll add state into the mix.

Here's a note from the horse's mouth on the difference between props and state:

State is reserved only for interactivity, that is, data that changes over time.

Thinking in React

We'll add state to the <App />.

  var App = React.createClass({
    getInitialState: function () {
        return {
            tabs: tabs,
            currentTab: 1
        };
    },
    // ...

Then we'll change the changeTab method like so:

  // ...
changeTab: function (tab) {
    this.setState({ currentTab: tab.id });
},
// ...

Next, we change the properties on the <Tabs /> call (still inside the <App /> component).

  <Tabs
    currentTab={this.state.currentTab}
    tabList={this.state.tabs}
    changeTab={this.changeTab}
/>

We also need to add a hook for the CSS to know when the current tab is selected. This is inside the <Tab /> component.

  <li className={this.props.isCurrent ? 'current' : null}>
    <a onClick={this.handleClick} href={this.props.url}>
        {this.props.name}
    </a>
</li>

That something ? [something else] : null syntax is a ternary operator. It's a very terse if/then/else.

And for the kludgiest part of our exercise, we'll add the bits of content that we'll show and hide depending on which tab is selected. A <Content /> component!

  var Content = React.createClass({
    render: function(){
        return(
            <div className="content">
                {this.props.currentTab === 1 ?
                <div className="mike">
                    <img src="http://s.mlkshk.com/r/104TN" />
                </div>
                :null}

                {this.props.currentTab === 2 ?
                <div className="donnie">
                    <img src="http://s.mlkshk.com/r/103AG" />
                </div>
                :null}

                {this.props.currentTab === 3 ?
                <div className="raph">
                    <img src="http://s.mlkshk.com/r/JAUD" />
                </div>
                :null}

                {this.props.currentTab === 4 ?
                <div className="leo">
                    <img src="http://s.mlkshk.com/r/ZJPL" />
                </div>
                :null}
            </div>
        );
    }
});

There's our friend the ternary operator again. This part of my example is meant to be thrown away, but hopefully give you an idea of what kinds of things are possible. It's worth noting that there's not a lot of logic you can (or should) put in one of these render statements. This is just part of a component after all, not a template.

And here's the final result. Be sure to check out the Result tab!

Important Takeaway

Something I want to highlight is that the state of the application is defined as high up as possible. If it were defined in either the <Tabs /> or <Content /> alone, you wouldn't have a way to tie them together. As it is now, we change the state from the <App /> and everything else falls into place automatically.

I hope this has helped someone get a better grasp of what this brave new world is all about. I know I need all the help I can get.

In case you want to use React on CodePen, check out this blog post.


37,001 5 22