Beginner’s Guide to React.js, With Examples

React.js is a JavaScript library that was created by Facebook. It is often thought of as the “view” in a model-view-controller (MVC) user interface. This makes sense when you consider the fact that the only function that must be implemented in React is the “render” function. The render function provides the output that the user sees (the “view”).

Let’s take a look at why you may want to use React and how to set up a basic interface.

Download the source code

You can download all of the files associated with this tutorial from here.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Learn React online

If you are keen to learn React from the ground-up feel free to check Learn and Understand React JS on Zenva Academy which covers all the basics + lots of bonus topics like React Router and Flux.

Tutorial requirements

  • This tutorial assumes that you have at least a beginner’s grasp of HTML and JavaScript.
  • You will need to download the React library if you want to go beyond the testing phase. We show you how to get around this during testing.
  • You will need a text editor of some sort. Notepad++ is popular for those on Windows machines, and TextMate is popular on a Mac. Editors that highlight code are preferable.
  • Normally, you would incorporate React into a larger application. If you want to test the basic code with external data files at the end of the tutorial, you will need to use a local or remote web server to get the page to work. MAMP is popular on Mac, and WAMP is most common on Windows machines. You can also use a lightweight Mongoose web server, or Python’s HTTP server. Many people use React with Node.js, so you can also use a Node.js server. The React library download page (above) also includes a server and other options.

Downloading React and getting started

There are many options for downloading and installing React and its various add-ons, but the fastest way to get started and begin playing around with React is to simply serve the JavaScript files directly from the CDN (as described on the React GitHub page… the most common CDN options are listed there):

<!-- The core React library -->
<script src="https://fb.me/react-0.14.1.js"></script>
<!-- The ReactDOM Library -->
<script src="https://fb.me/react-dom-0.14.1.js"></script>

Both the download pages go into detail on the various ways to download, install, and serve React in various formats, but we’re going to stick with this most basic option so we can focus on learning how to code with the React library itself. It’s a good idea to have the React API open while you work for reference.

From there, we create an index.html file, and a main.js file. I’ve also included a css file for basic styling:

<!DOCTYPE html>
<html>
  <head>
    <title>Learn Game Development at ZENVA.com</title>
    <!-- Just for basic styling. -->
    <link rel="stylesheet" href="assets/css/base.css" />
    <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>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/babel" src="main.js"></script>
  </body>
</html>

In order to get around using a server while testing, I’m calling the React.js, react-dom.js, and the browser.min.js babel-core files from the CDN. You wouldn’t want to do this in production. The babel-core file allows us to use JSX, and the script type must be “text/babel” in order for it to work properly. Our main JavaScript code goes in main.js, and that’s where it all starts.

Why React is better with JSX

Most React implementations make use of JSX, which allows you to put XML-like syntax right within JavaScript. Since React displays output as it’s main function, we will be using HTML in just about every component. JSX simplifies the code that would normally have to be written in JavaScript, which makes your code much more readable and simplified.

JSX is not required, but consider the difference between two very simple statements. The following statement is created without JSX:

var element = React.createElement('div', { className: 'whatever' }, 'Some text');

The following is with JSX:

var element = <div className="whatever">
   Some text
</div>

As you can see, the JSX code is much easier to read. Now that we have a basic understanding of what our output syntax will look like, let’s dig in and learn the building blocks of React.

Understanding React components

React is based on components and states. This is what makes React such a popular library. When you want to create an application, you usually break it into simpler parts. When programming with React, you will want to break your interface into its most basic parts, and those will be your React components.

Components are wonderful because they are modular and reusable. You can take a basic component used in one area of an application and reuse it in others without having to duplicate code. This helps to speed up development.

Components can be nested, so that the most basic components can be grouped into a parent component. For example, if you were to create a home listing interface with React, the top level component would be the home list itself. Within the list, you would have a description of a single home. Within the home component, you would have the address of the home, as well as other small components such as a photo, perhaps a favorite or save button, and a link to view details and a map.

layout-exampleNow let’s see how this information can be updated when it changes.

React component states

Component states are what give React its name. Any time a component’s state changes, its “render” function is called, updating the output. In essence, each component “reacts” to changes, which is handy for any user interface. Data stored in a state should be information that will be updated by the component’s event handlers (changes that should update in real time as the interface is being used).

If we were to have a home listing, any number of things may change in the database. New photos could be added, and a home can be bought and sold. You wouldn’t necessarily want any of these things to update in real time in the interface.

One thing that may change very quickly, however, would be the number of times a home is saved (or favorited or liked) by a user. The little component that displays the number of saves could update as soon as the person clicks the Save button by updating the state the moment the button is clicked. Let’s build the Saves component to show what this would look like:

var Saves = React.createClass({
  getInitialState: function(){
    return {
      saved: false,
      numSaves: 0
    }
  },
  handleSubmit: function(e) {
    e.preventDefault();

    var saved = false;
    var numSaves = this.state.numSaves;
    
    if (this.state.saved === false) {
      saved = true;
      numSaves++;
    } else {
      numSaves--;
    }
    this.setState({
      numSaves: numSaves,
      saved: saved
    });
  },
  render: function() {
    var savedText = '';
    var submitText = 'Save';
    if (this.state.saved) {
      savedText = 'You have saved this home.';
      submitText = 'Remove';
    }
    
    return (
      <div className="saves">
        <form onSubmit={this.handleSubmit}>
          <input type="submit" value={submitText} />
        </form>
      {this.state.numSaves} saves. {savedText}
      </div>
    );
  }
});

This won’t actually do anything yet, because we don’t have any statement to call on Saves. Still, this component describes what we do with components and states. You also won’t find this code anywhere in the files, because we will have to move things around a bit to make it work the way we want, but this is fine for now.

You may notice a naming convention right away. Most element names start with a lowercase letter, followed by capitalization. The names of React classes, however, begin with an uppercase letter. We then have the React.createClass() function, which creates our component.

The render method is that most-important method that produces the actual output, and is normally placed last in the component. As you can see, the output depends on the value of two states: saved and numSaves. Here’s what the output will look like when the user has saved the home:

Screen Shot 2015-09-30 at 9.29.34 AM

And when they have not saved the home:

Screen Shot 2015-09-30 at 9.29.22 AM

Just don’t include computed data in a state. What that means in this case is that, while you want to update the number of saves in the state when the Save button is clicked, you don’t want to save the following in the state:

this.setState({numSaves: numSaves + ' saves.'});

Save the addition of the string for the render function. All we want to save in the state is the data that gets updated by the component’s event handler, and that is simply the number of favorites.

You can also see JSX at work in the render method. The return value (just don’t forget the parentheses around the return output!) appears to be just regular HTML right within your JavaScript code! Well, not exactly. JSX is JavaScript, so the “class” attribute is discouraged. Instead, use “className.” In addition, JavaScript expressions used as attribute values must be enclosed in curly braces rather than quotes.

Because we are dealing with states, we need to set an initial state so that the state variables will always be available in the render method without errors. This is why we use the getInitialState() method at the top of the component.

The handleSubmit function is where we handle the pressing of the Save (or Remove) button. We first have to call preventDefault() in order to prevent the form from being submitted the normal way. We then process the data, so that the user will save the home if it’s not already saved, or remove it from their saves if it is saved. As soon as we save the new state at the end of the function, the render method will be called automatically, which will update the display. Now, let’s look at the rest of the example in more detail.

How to use props

Components pass properties to their children components through the use of props. One thing to keep in mind is that props should never be used to determine the state of a component. A property would be something such as the address of a home, passed from the listing component to the individual home component. The state, on the other hand, should depend on data that may be updated, such as the number of times people have saved the home.

Let’s look at the rest of this basic example. Taking into account the proper use of props and states, you may notice that there are some problems with this code:

var HomeListing = React.createClass({
  render: function() {
    return (
      <div className="homeList">
        <Home
          key={0}
          id={0}
          isSaved={false}
          photo="assets/images/home.jpg"
          address="12345 Beverly Dr"
          numSaves={52}
        >
          This is a home in the city
        </Home>
      </div>
    );
  }
});

var Home = React.createClass({
  render: function() {
    return (
      <div className="home">
        <span className="homeAddress">
          {this.props.address}
        </span>
        <Photo src={this.props.photo}></Photo>
        <span className="homeDescription">
          {this.props.children}
        </span>
        <Saves
          id={this.props.id}
          isSaved={this.props.isSaved}
          numSaves={this.props.numSaves}
        ></Saves>
      </div>
    );
  }
});

var Photo = (props) => {
  return (<div className="homePhoto">
    <img src={props.src} />
  </div>);
};

var Saves = React.createClass({
  getInitialState: function(){
    return {
      saved: this.props.isSaved,
      numSaves: this.props.numSaves
    }
  },
  handleSubmit: function(e) {
    e.preventDefault();

    var saved = false;
    var numSaves = this.state.numSaves;
    
    if (this.state.saved === false) {
      saved = true;
      numSaves++;
    } else {
      numSaves--;
    }
    this.setState({
      numSaves: numSaves,
      saved: saved
    });
  },
  render: function() {
    var savedText = '';
    var submitText = 'Save';
    if (this.state.saved) {
      savedText = 'You have saved this home.';
      submitText = 'Remove';
    }
    
    return (
      <div className="saves">
        <form onSubmit={this.handleSubmit}>
          <input type="submit" value={submitText} />
        </form>
      {this.state.numSaves} saves. {savedText}
      </div>
    );
  }
});

ReactDOM.render(
  <HomeListing />,
  document.getElementById('content')
);

For this basic example, we are just going to hard-code a home listing. It all starts at the bottom, where we have the ReactDOM.render() call. Version 0.14 of React separated React into two modules: React and ReactDOM. ReactDOM exposes DOM-specific methods, and React includes the core tools shared by React on different platforms. <HomeListing /> is basically a call to a component, in XML-style code. The naming convention states that regular HTML code is lowercase, while component names are capitalized. Everything will be placed in the “content” tag, which is included in the index.html file.

Normally, the HomeListing tag would include attributes that tell the component where to grab data, such as the location of a file URL. These attributes would be called using props. For now, we will focus on other props within our nested components. The HomeListing component in this example consists only of a render function, which calls on a nested component called “Home.” The call to Home contains all the attributes needed to describe the home listing, with JavaScript attribute values (including raw numbers, as well as true and false values) in curly braces.

The Home component is where we see our first use of props. Basically, any custom attribute sent through when calling a child component may be accessed through this.props. The most unique of these is this.props.children. The “children” property accesses whatever was included within the opening and closing tags of the call to the component (not including the attributes).

Notice in the call to the Home component that we include a “key” attribute, as well as an “id” attribute with the same value. The key is used internally by React, and is not available as a prop. It allows React to keep track of components that may be shuffled or removed. Since we also need some sort of id for our application, we pass in a second “id” attribute with the same value, which may be used as a prop.

Most of our output is displayed directly at the Home level, but we also call on two more children components: Photo and Saves. Photo doesn’t really need to be a child component in this instance, but it’s common for photos to have special features, which could be included in the future. Because it’s so small, it uses special syntax available to stateless components that have only a render method and nothing else. As you can see, the syntax allows the component to be extremely small and simple. The most important component in this case, however, is the Saves component. First, let’s take a look at our output from this code:

Screen Shot 2015-09-29 at 7.35.00 PMIt pretty much looks like what we want, doesn’t it? Well, not so fast. As you can see from the Saves component (which we discussed above), all the action is happening right here. The output shows that 52 people have saved the home before you. The problem is, how does the application save any new information. How will it “remember” that you saved the home too?

This is where things get just a little more complicated. First of all, you would normally include React as one piece of a larger app that will do all the processing of the data, where data is pulled from a database or file, then saved back to the database or file as the interface is being used. For now, we can hard-code this data as JSON, and show you at what point the data would be saved at the other end.

Organizing your interface

What we need to do is pull data from the top level component, and save data at the top level as well. This is because the total number of saves is being shared with all users. If our application was sharing information that is only relevant to each individual user, we could pull and save data in a child component, because what other people see wouldn’t matter.

Here is our updated code:

var HomeListing = React.createClass({
  /*One option is to pull data from, and save data to,
    a json url for testing. On a larger scale,
    this React output would be part of a larger app
    where the data is saved in a database as part of
    an MVC, where React is the View in the
    Model-View-Controller
  */
  loadHomesFromServer: function() {
    //We're going to hard-code this information for testing purposes.
    var homes = [
      {
          "address": "12345 Beverly Dr",
          "description": "This is a home in the city",
          "photo": "assets/images/home.jpg",
          "saves": 52,
          "saved": false
      },
      {
        "address": "98765 Tweety Ln",
        "description": "This is a home in the suburbs",
        "photo": "assets/images/home.jpg",
        "saves": 123,
        "saved": true
      },
      {
        "address": "1 Small St.",
        "description": "This is a nice little country home",
        "photo": "assets/images/home.jpg",
        "saves": 189,
        "saved": false
      }
    ];
    this.setState({homes: homes});
  },
  loadSavesFromServer: function() {
    //Again, we hard-code for testing
    var saves = [
      {
        "saves": 52,
        "saved": false
      },
      {
        "saves": 123,
        "saved": true
      },
      {
        "saves": 189,
        "saved": false
      }
    ];
    this.setState({saves: saves});
  },
  toggleSave: function(index) {
    
    var saves = this.state.saves;
    
  	if (saves[index].saved) {
      saves[index].saves--;
      saves[index].saved = false;
		}
		else {
  		saves[index].saves++;
      saves[index].saved = true;
		}
		this.setState({
			saves: saves,
		});
    
    //This is where we would save the information if this were part of a larger app
    return saves[index].saved;

	},
	getInitialState: function(){

		var saves = [];
    var homes = [];
    
		return {
      saves: saves,
      homes: homes
    }
	},
  componentDidMount: function() {
    this.loadHomesFromServer();
    this.loadSavesFromServer();
    //If we were updating the saves, we could continuously poll the server,
    //and update the Saves information when something changes
    //setInterval(this.loadSavesFromServer, this.props.pollInterval);
  },
  render: function() {
    //We need to set these variables (including the toggleSave function)
    //so they can be used within the map function below. Otherwise, they
    //would be outside the function's scope
    var saves = this.state.saves;
    var toggleSave = this.toggleSave;
    
    var homeNodes = this.state.homes.map(function(home, index) {
      
      if (typeof(saves[index]) == "undefined") {
        saves[index] = {saves: 0};
      }
      //the key is React-specific, and is especially important when
      //components can be shuffled or removed. it is NOT available
      //as a prop, so we need a separate id for that.
      return (
        <Home
          key={index}
          id={index}
          onToggleSave={toggleSave}
          isSaved={saves[index].saved}
          photo={home.photo}
          address={home.address}
          numSaves={saves[index].saves}
        >
          {home.description}
        </Home>
      );
    });
    return (
      <div className="homeList">
        {homeNodes}
      </div>
    );
  }
});

var Home = React.createClass({
  toggleSave: function(index){
    //We have to do a second pass to the top level parent,
    //since that is where the entire list resides.
    return this.props.onToggleSave(index);
  },
  render: function() {
    return (
      <div className="home">
        <span className="homeAddress">
          {this.props.address}
        </span>
        <Photo src={this.props.photo}></Photo>
        <span className="homeDescription">
          {this.props.children}
        </span>
        <Saves
          id={this.props.id}
          handleSave={this.toggleSave}
          isSaved={this.props.isSaved}
          numSaves={this.props.numSaves}
        ></Saves>
      </div>
    );
  }
});

var Photo = React.createClass({
  render: function() {
    return (
      <div className="homePhoto">
        <img src={this.props.src} />
      </div>
    );
  }
});

var Saves = React.createClass({
  handleSubmit: function(e) {
    //We prevent the default action of submitting the form
    //so we can stay on the page
    e.preventDefault();
    
    //We have to pass this up to the parent
    var isSaved = this.props.handleSave(this.props.id);
  },
  render: function() {
    var savedText = '';
    var submitText = 'Save';
    if (this.props.isSaved) {
      savedText = 'You have saved this home.';
      submitText = 'Remove';
    }
    
    return (
      <div className="saves">
        <form onSubmit={this.handleSubmit}>
          <input type="submit" value={submitText} />
        </form>
      {this.props.numSaves} saves. {savedText}
      </div>
    );
  }
});

React.render(
  <HomeListing url="homes.json" savesUrl="saves.json" pollInterval={10000} />,
  document.getElementById('content')
);

The first difference here is that React.render() calls on the HomeListing component using a few attributes. These attributes are not being used at the moment, because that would require the use of a server of some sort (see the requirements section above for links). You can easily move the homes data to a homes.json file, and the saves data to a saves.json file. Another option is to create some database calls to pull the data, and save the updated data.

You’ll now see that the HomeListing component does all the work. The reason we have separated the saves information from the homes information is that we don’t want to update changes to the homes in real time. Changes to home information just don’t happen often enough to make it worth the cost in resources to update every single thing on the page.

Another change you would probably make when pulling “real” data from a database would be to include whatever key is used to save a home in the database. That key would be used when referencing the homes, as well as the save data for each home. For now, we’re just counting on the JavaScript map method to give us array indexes that line up between the two lists of homes and saves data, simply because the arrays are in the correct order and the same size.

Here is the output of the new JavaScript file:

Screen Shot 2015-09-29 at 7.34.15 PMIt’s pretty much the same as the old output, except that the interface now works properly! We still aren’t saving the data, but you’ll see that there is a comment in the toggleSave() function (which is a custom function), showing where you would save the new data to a database, or to a json file. We also make use of the React method componentDidMount(). This method is automatically called once when the component has finished rendering. This is the perfect place to load our information. It’s also the best place to put any polling function, such as the setInterval function, for updating any changes to the saves in real time.

You’ll also see that the custom load functions, which include JSON-style data, have a setState() call at the end. Even though we won’t be updating the home data in real time, setting it in a state makes it easier to populate the output with the correct data after the component is loaded. The reason we separate the saves into another state is so that you can comment out the setInterval() call to update only the save data in real time, and nothing else. The interval time can be sent through props, as it is in the call to HomeListing.

setInterval(this.loadSavesFromServer, this.props.pollInterval);

In the HomeListing render() method, we map out all the data to include each individual call to the Home component, along with all the attributes for each. We have to set some variables to anything that uses “this” which need to be accessed within the map method, because they are outside its scope.

var saves = this.state.saves;
var toggleSave = this.toggleSave;

You’ll also notice that there is a new attribute that is set to our custom toggleSave() function. That is how we are going to save information updates initiated in child components. The child component must call the parent function using props. In the Home component, you’ll see that the toggleSave() custom function calls this.props.onToggleSave(index). I deliberately made the names different to show that you must call the function using the attribute name that was passed in rather than the actual name of the function in HomeListing.

return this.props.onToggleSave(index);

Another thing that can be confusing to people is that attributes are not automatically passed down to all the nested children when they are nested more than one level. You’ll see that the function attribute passed to Home must also be passed down to the Saves component, and it can have a completely different name! The same goes for all the other props. Here, we pass the props sent to the Home component down the next level to the Saves component:

<Saves
  id={this.props.id}
  handleSave={this.toggleSave}
  isSaved={this.props.isSaved}
  numSaves={this.props.numSaves}
></Saves>

Note that the toggleSave() function call could have been passed directly through as another props value, but we can also do as we did here and call a local function first, which then calls the parent function through props. That gives you the ability to make any additional changes.

So now that we have all that sorted out, you should know that each component should be separated out into separate JavaScript files, and organized into a “components” folder. This is for when you have a more complex design, and have a local or remote server running. Then, each component opens its children components using require().

Comments or questions?

Do you have any questions about this article, or about React.js in general? What else would you like me to write about? Let me know in the comments section below.