Chapter 1. Introducing React

I'm working on the book full-time, and would love to solicit some early feedback from interested readers. Sign up for the book announcement mailing list (no spam, ever) and I'll send you the 39 page introduction and first chapter in PDF format.


Dearest reader, this is an early version of the forthcoming book, "Easy React: Build Powerful Web Apps Using Modern JavaScript Technologies". As such, you'll quite possibly find a mistake or two, and perhaps even a horrible error or half-truth. Such is life in the dangerous world of reading technical book drafts. I can however assure you I'm working tirelessly to complete a quality book, and very much value your feedback. E-mail me anytime at wj@wjgilmore.com.

Chapter 1. Introducing React

React is a JavaScript library intended to reduce the complexity associated with building interactive applications consisting of data that changes over time. It does so by presenting a straightforward solution for efficiently detecting these changes and updating the application accordingly.

While there are certainly other solutions that offer similar capabilities (AngularJS and Ember.js come to mind), it's important to understand React is not a complete JavaScript framework in the sense one might consider AngularJS or Ember.js to be "complete". React deals expressly with your application's presentation layer, and could care less about what you use to power the other aspects of your project. This limited scope is precisely what makes React relatively easy to learn, and in fact I guarantee by the end of this chapter you'll have a fairly solid grasp of React's key capabilities. An increasing number of well-known companies seem to agree, as not only do creators Facebook and Instagram use React for their applications, but so does Atlassian, Khan Academy, and Code Academy, to name a few.

In this opening chapter we'll get acquainted with React fundamentals, beginning with installing the library and creating a simple React-driven project. We'll then repeatedly refactor this introductory example in order to introduce a laundry list of React features such as JSX (JavaScript Syntax Extension), composable components, and two very important React concepts known as props and state. Finally, you'll learn all about React's various component lifecycle methods, and work through a comprehensive example demonstrating exactly when and how each method executes in conjunction with a rendered component.

Let's kick things off by installing React and cloning a simple starter repository I've created to help you begin interacting with the library as quickly as possible.

Installing React the Easy Way

There are a couple of different ways in which you can install React, notably either by referencing the library via the Facebook CDN or installing it on the server side using a JavaScript package manager such as npm. I strongly suggest all readers (including you JavaScript gurus) just reference the CDN for the examples found throughout the majority of this chapter, allowing you to focus exclusively on React syntax rather than potentially battle JavaScript workflow issues. In the next chapter you'll learn how to install and configure React within a more organized and manageable development environment.

Installing the Easy React Starter Project

Because most of the examples found in this chapter involve executing React code on the client-side, you won't need to install and configure a web server at this time. Even so, because we'll be using cool technologies such as Node.js and Express later in the book, I nonetheless thought it made sense to serve these opening examples using a basic Node.js-based web server. Even if you don't have any prior Node.js experience you should be able to get started in less than five minutes.

The components you create in this chapter will not be very eye-appealing for the simple reason that React's approach to managing integrated HTML and CSS is pretty much guaranteed to elicit heart palpitations among seasoned web developers, and therefore I've devoted the entirety of chapter 3 to the matter of CSS integration in order to not only explain how to properly integrate HTML and CSS into your React components, but additionally explain the reasoning behind the React team's radical departure from convention. So for now, let's focus solely on React fundamentals, and I promise we'll make things look cool real soon.

For starters, you'll need to install Node.js. Although I discuss Node.js installation at length in chapter 5, the instructions are frankly overkill because installation is a breeze no matter what your operating system. Head over to https://nodejs.org/ now and you'll be greeted with a large INSTALL button which you can press to download an operating system-specific Node.js installer. Alternatively, if you're the sophisticated type, consider using a package manager such as OS X's Homebrew.

Once installed, clone the Easy React Starter repository hosted over on my GitHub account. I'll presume per the book's introductory prerequisites you understand what it means to clone a repository; if not please refer back to the introduction for a useful learning resource. Go ahead and clone the project now:

$ git clone https://github.com/wjgilmore/easy_react_starter

Various examples presented throughout this chapter are associated with different branches found in this repository, however this opening example uses the master branch.

Once cloned, enter the easy_react_starter directory and run the following command, which will install a few necessary Node packages used to power the server:

$ npm install

After this command completes execution, you'll find a new directory in the repository called node_modules. This contains the third-party packages which were just installed via the above command. Do you delete or otherwise mess with this directory. Next, run the following command to start the server:

$ node server.js
Server started: http://localhost:3000/

Open up a browser and navigate to the URL http://localhost:3000/test.html. If you see the message, "It Worked!", congratulations you're running a local Node-powered web server. If you do not see this message, e-mail me and I'll help you troubleshoot the problem. Incidentally, you can stop the server by pressing Ctrl-c.

In addition to the server, this repository contains a few starter files which we'll use to get acquainted with React fundamentals. Don't worry, after the first example you'll begin writing plenty of React code yourself, so get prepared to start banging on that keyboard!

Using the Facebook CDN

In the next chapter I'll show you how to install and manage the React library alongside other server-side JavaScript technologies. However sorting out the various project configuration details can take a bit of time and effort, and so we're going to instead get things quickly rolling in this chapter by linking directly to the library via the Facebook CDN.

If you head over to the React downloads page you'll find four different CDN-based versions, including two for production and two for development. There are two versions of each because an optional version contains an array of experimental add-ons. You can learn more about these add-ons in the React documentation. For the time being we'll just use the standard development version minus the add-ons.

At the time of this writing React 0.14 beta had just been announced, but is not yet listed on the React downloads page. Because we're living on the cutting edge, the repository instead uses the popular CDNJS service to import 0.14.

When experimenting with and developing React-based applications you'll want to use the development build because it's uncompressed and includes inline documentation should you want to peruse the source code. Additionally, the development version will produce warnings highlighting common mistakes. By contrast, the production version is compressed for optimization reasons and suppresses error messages, so you'll want to swap out the development build for the production build when deploying to production.

Perusing the React source code can be very insightful. For instance, navigate to the CDNJS hosted library and have a look through the code and corresponding comments.

Return to the starter repository, and open the file index.html found in the public directory. You'll find a standard HTML template containing two important lines, both of which I've highlighted:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Welcome to VocabGiant</title>
  leanpub-start-insert
  <script src=".../libs/react/0.14.0-beta1/react.js"></script>
  <script src=".../libs/react/0.14.0-beta1/JSXTransformer.js"></script>
  leanpub-end-insert
</head>
<body>
  <div id="app"></div>
</body>
</html>

The first highlighted line references the CDNJS-hosted library (I've truncated the URL here due to reasons of space), loading a recent version of the React library into the browser. Doing so will give you access to React syntax, which we'll use to create a variety of examples throughout this chapter. The second highlighted line loads Facebook's in-browser JSX transformer. JSX is JavaScript extension that allows you to create React components using a succinct, convenient syntax. When running React applications in the browser, this transformer will detect the JSX and transform it into JavaScript syntax supported by the browser. Don't worry too much about JSX or transformation for now as I'll devote ample time to the topic later in this chapter.

Inside <body> I've added a DIV identified by the app ID. This will house the rendered React component. You're free to render the component anywhere you please within the DOM, however you'll receive a warning when attempting to render it directly within <body> due to side-effects which could arise when other libraries are additionally attempting to interact with the <body> element.

With React and the JSX transformer referenced it's time to create your first component!

Creating Your First React Component

As I briefly mentioned in the book's introduction, one of React's most attractive features is the fact a React "application" can consist of hundreds of components containing thousands of lines of code, or just one component containing just a few scant lines of code. This means you can ease into the world of React without devoting untold amounts of time to research and configuration. Let's prove this assertion by adding a simple component to the starter application's web template.

Return to index.html and add yet another <script> declaration which will make a simple React component available to the page:

<script type="text/jsx" src="js/app.js"></script>

However, you'll want to insert it between the <body> tags, rather than within the <head>. The modified index.html file should look like this (new line emphasized):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Welcome to VocabGiant</title>
  <script src=".../0.14.0-beta1/react.js"></script>
  <script src=".../0.14.0-beta1/JSXTransformer.js"></script>
</head>
<body>
  <div id="app"></div>
  leanpub-start-insert
  <script type="text/jsx" src="js/app.js"></script>
  leanpub-end-insert
</body>
</html>

If you're relatively new to JavaScript then you might be wondering why this <script> element wasn't placed alongside the others. It is because the JavaScript is going to execute as soon as it is made available to the browser, which presents a problem if the JavaScript is intended to interact with the page's Document Object Model (DOM). If the JavaScript executes before one or more of the required page elements are available, then logically the script isn't going to work as intended. There are more sophisticated ways in which JavaScript can be configured to not execute until after the page DOM is available, however for the moment doing it in this manner is just fine.

Additionally, note the use of the text/jsx MIME type. This is necessary because the JSX transformer library will use this MIME identifier as the cue for transforming the associated code into browser-supported JavaScript.

With the example React component now available to the HTML template, return to your browser and navigate to http://localhost:3000 (restarting the server by running node server.js if necessary), and you should see the message Welcome to VocabGiant in your browser (see the below screenshot).

Your First React Component

Your First React Component

So how did this welcome message find its way into the page considering it isn't actually included in index.html? It was rendered by way of the React component which resides in public/scripts/app.js. Open that file now and you'll find the following code:

var Hello = React.createClass({
    render: function() {
        return (
          <h1>Welcome to VocabGiant</h1>
        );
    }
});

React.render(<Hello/>, document.getElementById('app'));

Let's review each line of this code:

var Hello = React.createClass({

This opening line kicks off the creation a new React component using the React object's createClass method. This React object was automatically made available when you loaded the React library via the CDN. Within createClass you'll define the component's markup and behavior, although for the moment we're just focusing on the former, which is returned using the render property:

render: function() {
    return (
      <h1>Welcome to VocabGiant</h1>
    );
}

The render property is ultimately responsible for returning the component's content. Note how the return statement doesn't require what otherwise appears to be a string to be encapsulated in quotations. If we were writing native JavaScript code then this would produce a syntax error however keep in mind we're writing JSX (JavaScript syntax extension), which is a JavaScript extension Facebook created to reduce the amount of code you'd otherwise have to write to create components. But because browsers don't understand JSX, how is this code being executed in the browser? I'll explain this in more in the next section, "Introducing JSX".

In the meantime, keep in mind I said render is ultimately responsible for returning the component's content, but it isn't strictly limited to that. You can (and often will) include additional logic inside render. For instance here's a trivial variation of the above example which just moves the returned HTML into a variable:

var Hello = React.createClass({
    render: function() {

      var welcome = <h1>Welcome to VocabGiant</h1>;

      return (
        welcome
      );
    }
});

Let's conclude the review of this code by having a look at the lone remaining line:

React.render(<Hello/>, document.getElementById('app'));

The React object's render method is responsible for rendering the identified component (<Hello/>) within a designated DOM container, in this case the DIV identified by the ID app. Note how the first parameter formats the Hello variable containing the component object, specifying it using XML syntax (<Hello/>). This is additional shorthand syntax provided to you by JSX, otherwise you'd be required to write:

React.render(React.createElement(Hello, null), document.getElementById('app'));

In any case, when the page is loaded into the browser, the component will be injected into the <app> element, producing the following output:

<body>
    <h1 data-reactid=".0">Welcome to VocabGiant</h1>
</body>

This outcome was expected, although that data-reactid attribute probably comes as a surprise. React will automatically tag each component with a unique ID in order to easily find those components later should they require updating. If the idea of these IDs stampeding all over your project's rendered pages makes you uneasy, various discussions within React's GitHub issue tracker seem to indicate they will be removed once a more suitable solution is implemented.

Of course, you're not constrained to using an element identified by any particular name (such as app). For instance, add the following div to your index.html file, inside body:

<body>
  <div id='greeting'></div>
</body>

Next, modify the render call inside app.js to look like this:

React.render(<Hello/>, document.getElementById('greeting'));

Reload the browser and you'll see the same greeting message, but this time it is embedded inside the <div> identified by the ID example. If you view the page source within your browser you'll see the result is as expected:

<div id="example">
    <h1 data-reactid=".0">Welcome to VocabGiant</h1>
</div>

So if we're writing these components in JSX syntax, how are they even rendered to the browser since browsers don't understand JSX? For that matter, why are we writing them in JSX in the first place? I'll answer both of these questions next.

Introducing JSX

Facebook created JSX (JavaScript syntax extension) as an alternative syntax for writing React components. I stress alternative because you are not required to use JSX! It is perfectly acceptable to use standard JavaScript to create and render your components. However, as you'll soon see, JSX does save the hassle of typing quite a few extra keystrokes, and ultimately produces much more readable code. The importance of this latter improvement cannot be understated, particularly once you begin creating components hierarchies (component hierarchies are discussed in the next section).

As you've already seen, JSX looks quite similar to standard JavaScript syntax. However, because JSX is an extension and not part of the ECMAScript specification, browsers logically do not understand it. This means the JSX syntax must be converted, or transformed, into standard JavaScript so it can subsequently be executed within the browser. This might seem like a lot of work but as you've already seen Facebook offers a JSX transformer which can be embedded into your web page and automatically do all of the difficult work associated with the transformation.

So how much typing will JSX save you? Returning to the earlier example, here's the JSX code found in app.js:

var Hello = React.createClass({
    render: function() {
        return (
          <h1>Welcome to VocabGiant</h1>
        );
    }
});

React.render(<Hello/>, document.getElementById('app'));

And here's is the same code transformed into native JavaScript:

var Hello = React.createClass({displayName: "Hello",
  render: function() {
    return (
     React.createElement("h1", null, "Welcome to VocabGiant")
    );
  }
});

React.render(React.createElement(Hello, null), document.getElementById('app'));

At a glance it's clear the JSX code is more concise then the transformed result. As your React application grows in size, JSX will not only result in a significant reduction of code, but will also dramatically improve readability (more about this latter advantage in the next section.)

Of course, repeatedly transforming the same JSX every time a page is rendered isn't particularly efficient, and in fact doing so in this fashion is really only recommended during this early exploratory phase. In the next chapter you'll learn how to precompile your JSX using server-side JavaScript tools.

If you'd like to experiment with JSX syntax and view the transformed JavaScript, check out Facebook's web-based JSX Compiler.

Creating Component Hierarchies

Of course, the typical React application is going to consist of much more than a single component, and you won't be using this powerful technology to output static content such as that demonstrated in the above examples. In a real-world application you'll want to create reusable components, some of which contain dynamic data, which can then be embedded within one another to create a component hierarchy. The React team refers to this key feature as composability. To understand the utility of using React to assemble component trees, consider the following simplified version of a typical VocabGiant screen:

Displaying a Vocabulary List

Displaying a Vocabulary List

This is a stylized bulleted list presenting a list of Italian vocabulary words and their English counterpart. Logically we want each list item's structure and styling to look uniform, so a list item should be encapsulated within a component. Further, the list items should be placed inside the list, therefore we need to loop over each list item and insert it into the list structure. The logic used to perform the iteration needs to reside somewhere, so let's create a parent component from which we'll iterate over each vocabulary term and generate a representative number of list item components.

Let's recreate a simplified version of this list in order to understand how components can be nested together in this fashion. Begin by deleting the Hello component declaration from app.js, replacing it with the following ListItem component:

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

Next, we're going to dynamically nest three ListItem components inside a List component. In a real-world application the number of list items would logically be determined by the number of records retrieved from a database, but for the purposes of this example we'll just use a simple array to simulate the behavior. Return to app.js and add the following List component, and then update the render method to point to <List />:

var List = React.createClass({
  render: function(){
    var listItems = [1,2,3].map(function(item){
      return <ListItem/>;
    });
    return (
      <div>
        <ul>
          {listItems}
        </ul>
      </div>
    );
  }
});

React.render(<List />, document.getElementById('app'));

Reload the browser and you'll see output like that found in the below screenshot:

Nesting List Items

Nesting List Items

Keep in mind at this point my only goal is to demonstrate component hierarchies; all we are doing is outputting static list items. Logically in a real application you'll want to populate those list items with dynamic data. I'll show you how to do this in just a moment.

Introducing the key Property

If you're running these examples with the browser console open (and I suggest you do), you probably noticed the following warning:

Warning: Each child in an array or iterator should have a 
unique "key" prop. Check the render method of List.

React requires that each child in an array include a unique key which React will then use for tasks such as subsequent filtering or reordering. Although we'll dive into the matter of passing dynamic data into components later in the chapter, it's worth providing an example now to remedy this warning:

var List = React.createClass({
  render: function(){
    var listItems = [1,2,3].map(function(item){
      leanpub-start-insert
      return <ListItem key={item} />;
      leanpub-end-insert
    });
    return (
      <div>
        <ul>
          {listItems}
        </ul>
      </div>
    );
  }
});

In this example I'm taking the easy way out and using the array values as component keys, but even so it is valid because each key value is unique. You'll want to ensure your keys are always constant and unique otherwise you'll wind up with inconsistent behavior and performance issues.

In the following chapters you'll encounter many more examples of composable components, however hopefully this simplified example is suffice to get your mind racing regarding what's possible. We'll return to this example repeatedly throughout the remainder of the chapter, repeatedly refactoring it as new React features are introduced.

Introducing Props and State

Your project's React components will typically be populated with data retrieved from a dynamic data source such as a database. But how is this data passed into the component? How does React keep track of this data and ensure that it is seamlessly updated should circumstances dictate it due to for instance a user-initiated event or server request? How does React ensure this data's life cycle is managed in such a way so as to prevent obscure bugs from arising due to inconspicuous modification?

In this section we'll talk about how React answers these questions by supporting two distinct types of data, known as props (shorthand for properties) and state. The difference between these two concepts are subtle yet important, so be sure to read this section carefully and e-mail me with questions.

I find the choice of terms props and state to be awkward and confusing. In order to avoid further confusion I'm not going to deviate from these terms, however would like to suggest that whenever you read the terms, "props bag" and "state bag", respectively. This is because props and state provide developers with a convenient and conventional solution for passing domain-specific, arbitrary data of different types around your React application. A "bag" is just a colloquialism for an object which you'll use to house this arbitrary data, so if you'd like just mentally substitute "bag" for "object".

Introducing Props

React attempts to eliminate much of the confusion and chaos typically associated with keeping a user interface synchronized with data changes by enforcing one-way data binding in which data flows from a parent to child component. The parent is responsible for managing the data life cycle, and the child responsible for the data's display. In order to enforce this convention, once data is passed from parent to child it should be treated as immutable. React's immutable data is managed within props.

Of course, this data might eventually change, but that decision will be made by a stateful parent component which will contain whatever logic is required to implement the UI update. Your application should generally consist of many stateless components, and relatively few stateful components. For the moment let's focus on the child (stateless) components and the props used to pass this data along.

You'll inject data into the props bag using a syntax that looks a lot like that used for HTML attributes:

<ListItem word='ciao' />

React knows your intent is to make the word attribute and it's associated value ciao available within props. You can then render the word value within the ListItem component by referencing the this.props.word attribute:

var ListItem = React.createClass({
  render: function() {
    return (
        <li>{this.props.word}</li>
    );
  }
});

The curly brackets tell React to interpolate whatever is found inside, which in this case is the this.props object's chore property.

Let's consider a somewhat more involved example involving passing props data into a component, revising the previous example to pass an array of chores into the list. I've just showed you what an example <ListItem> component might look like, so let's create a parent <List> component and pass an array of words into the child <ListItem> component:

var List = React.createClass({
  render: function(){
    var words = ['ciao', 'giorno', 'mare']
      .map(function(item){
        return <ListItem key={item} word={item} />;
      });
    return (
      <div>
        <ul>
          {words}
        </ul>
      </div>
    )
  }
});

Reload the page and you'll see the terms presented in a manner similar to that found in the below screenshot.

Presenting Vocabulary Words

Presenting Vocabulary Words

While it's possible to populate a React-driven UI with solely props-driven data, in doing so you're not going to create a particularly compelling application. It's when you use both props in conjunction with the other type of React data, known as state that things really begin to get exciting.

Introducing State

Synchronizing an application's interface, user interactions, and underlying data stores has historically been a difficult and often error prone process. React removes much of the confusion through its enforcement of one-way data binding, or requiring parent components to be responsible for pushing data down the component tree to their children, and requiring children to send events up the component tree to their parents. This idea is so central to understanding React that I suggest taking a moment to conceptually visualize it before moving on.

Data that may change over time must be identified as state, meaning you'll pass it along using state. In doing so, React will keep track of this data in a manner that allows it to quickly identify and replace it should circumstances warrant (due to among other things a user-initiated event, a server request, or the lapse of time).

So what useful state-related feature might we integrate alongside the list of vocabulary terms? How about a search field that allows users to quickly look up a particular term? By "quickly", I'm referring to a real-time search experience in which the default list of terms appears to dynamically update the moment a user begins to type in the search field. The search field is an example of something you would represent using state because a change in value will necessitate an update of other parts of the page, namely which terms should be displayed given the provided filter string. Let's refactor the code found in the starter project to add a simplified version (stylistically, at least) of the search filter presented in the following screenshot.

Filtering Vocabulary Terms

Filtering Vocabulary Terms

Admittedly this example is a tad more involved than what you've seen thus far in the chapter. However this just presents an opportunity to introduce new React features! So let's start by creating an isolated version of the search form which will really get you excited about using state.

Reacting to User Input

Responding to user input is a prime example involving the use of state in your React application. In the context of the larger search filter example we will build a solution for passing user input into the logic used to filter the vocabulary list, however let's ease into this by focusing exclusively on how React is able to detect and respond to user input by assembling an isolated example.

Follow along with the code in this section by checking out the user_input branch of the easy_react_starter repository.

Specifically, we'll create an interface which detects user input and echoes that input in real-time to another part of the DOM. The below screenshot illustrates this behavior. I've typed in i love vocabulary, and that string is reflected below the text field in another div. Obviously this is going to be much more impactful if you checkout the user_input branch as described above and run the example, so consider doing that before reading any further.

Echoing User Input

Echoing User Input

To implement this example we'll create two components. The first is called SearchBox, and it looks like this:

var SearchBox = React.createClass({
    handleChange: function() {
      this.props.onUserInput(
          this.refs.filterTerms.value
      );
    },
    render: function() {
      return (
          <form>
            <input 
              type="text"
              id="filter"
              ref="filterTerms" 
              placeholder="Find term"
              onChange={this.handleChange}
              value={this.props.filterTerm} />
          </form>
      );
    }
});

As you can see, this component defines two functions, handleChange and render. The handleChange function is responsible for passing whatever value is found in the element identified by the ref attribute named filterTerms to the function named onUserInput which is defined in the parent component. Carefully review the code found inside handleChange to ensure you understand that we are not changing the value of a prop named onUserInput; we are passing the value of the element identified by the filterTerms ref into this.props.onUserInput. This handleChange function is triggered every time the value of the text field changes (by way of user interaction in this case), because it is attached to the text field via the JavaScript onChange function. This <SearchBox> component is rendered using the parent <Home> component, presented next:

var Home = React.createClass({

  getInitialState: function(){
    return {
      filterTerm: ''
    };
  },

  handleUserInput: function(filterTerm) {
      this.setState({
          filterTerm: filterTerm
      });
  },

  render: function() {
    return (
      <div>
        <br />
        <SearchBox 
          filterTerm={this.state.filterTerm} 
          onUserInput={this.handleUserInput} />
          <br />
        <div>{this.state.filterTerm}</div>
      </div>
    );
  }
});

React.render(<Home />, document.getElementById('app'));

This component defines three functions, including getInitialState, handleUserInput, and render. Let's review the role of each:

  • getInitialState: The getInitialState function will execute one time during the component's lifecycle, and is responsible for defining the component's initial state. As you can see we are managing a single state value called filterTerm, which is by default blank. I encourage you to change the initial value to something like sole and reload the page. You'll see that not only is the location where the user input is otherwise echoed will automatically be set to sole, but so will the filter field be similarly set!
  • handleUserInput: In this stateful parent component you need to identify what exactly should happen when the data is defined as being stateful. In this case we want to provide realtime filtering of the list of chores according to the supplied filter value, and so want to update the stateful filterTerm attribute to whatever is being passed into the function (via the child). You'll update the state using the setState method.
  • render: The render function performs the usual task of rendering the desired components. Because this is a parent component you can see we're rendering the child SearchBox component. Note how both the filterTerm state and the handleUserInput function are passed into the component as properties. Additionally we're outputting the stateful filterTerm value using the this.state bag.

With these two components in place, you're able to recreate the functionality depicted in the previous screenshot!

Creating a Real-time List Filter

Now that you understand how React can listen for and respond to user input, let's expand upon this concept and implement the vocabulary filter.

Follow along with the code in this section by checking out the vocab_filter branch of the easy_react_starter repository.

Let's begin with the component used to present each list item. This is really nothing new however for completeness' sake I'll include the component here:

var ListItem = React.createClass({
  render: function() {
    return (
        <li>{this.props.term}</li>
    );
  }
});

We're going to iterate over a vocabulary list, passing each term into the ListItem component in order to render another <li> element (via the <ListItem> component). Let's have a look at the component used to iterate over that list:

var ListItems = React.createClass({

  render: function(){

    var items = [];

    var filterTerm = this.props.filterTerm;

    this.props.terms.forEach(function(term){

      if (term.indexOf(filterTerm) != -1) {
        items.push(<ListItem key={term} term={term} />);
      }
    });

    return (
      <ul>
        {items}
      </ul>
    );

  }

});

This is a tad more involved than the previous component, yet also presents nothing new. The ListItems component receives two props attributes, including terms which contains an array of terms, and filterTerm which contains the filter string input by the user using the filter field. The component's render function iterates over each terms element, and if the string contained in filterTerm matches any substring of the current terms element, that element will be passed to the ListItem component and the returned content pushed onto the items array. Once all elements found in terms have been examined, the items array is inserted between the <ul> tags and returned.

Next up is the Home component. This component looks almost identical to the Home component presented in the previous example. It contains the ListItems and SearchBox components. Remember, you want to maintain state in as few components as possible, and those components should be parent components, so we'll maintain the filter field's state here. I'll present the component followed by an explanation:

var Home = React.createClass({

  getInitialState: function() {
    return {
        filterTerm: '',
    };
  },
  handleUserInput: function(filterTerm) {
      this.setState({
          filterTerm: filterTerm
      });
  },
  render: function(){
    return (
      <div>
        <SearchBox 
          filterTerm={this.state.filterTerm} 
          onUserInput={this.handleUserInput} />
        <ListItems
          filterTerm={this.state.filterTerm} 
          terms={this.props.terms} />
      </div>
    )
  }

});

Finally, we'll define an array of terms, and passed them into the ListUI component as a prop attribute:

var terms = ['mare', 'sole', 'sabbia', 'acqua', 'spiaggia'];

React.render(<Home terms={terms} />, 
  document.getElementById('app'));

So where is the SearchBox component? I didn't include it because it is identical to that used in the previous example! Hopefully this omission will serve to get you thinking about how React components can be reused in interesting ways. Incidentally, the SearchBox component is in the vocab_filter branch, so you won't have to recreate it in order to run the example.

Before moving on I suggest spending some time creating other components and experimenting with passing events upwards to parent components and props downwards from parent components to children components.

Reading and Rendering JSON Data

Although you'll learn all about incorporating a database and other types of data into your React applications later in the book, I've no doubt many of you are very interested to know how to read and render JSON and so thought we'd conclude this chapter with a brief introduction to the topic.

Follow along with the code in this section by checking out the json_loader branch of the easy_react_starter repository.

If you have a look inside the repository's json_loader branch you'll find a JSON file named vocabulary.json. It contains a list of Italian vocabulary terms and their English counterparts. Here's a snippet:

{
  "words": [
    {
    "origin": "accogliere",
    "translation": "to welcome"
    },
    {
    "origin": "affrettarsi",
    "translation": "to hurry"
    }
  ]
}

The example created in this section will retrieve the vocabulary.json file and render it to the browser window as depicted in the following screenshot:

Rendering JSON

Rendering JSON

The first two components used to render the JSON file offer nothing new as they're responsible simply with formatting the data as a series of list items:

var ListItem = React.createClass({
  render: function() {
    return (
     <li>{this.props.item.origin}</li>
    );
  }
});

var ListItems = React.createClass({
  render: function() {

    var listItems = this.props.items.map(function(item){
      return <ListItem key={item.origin} item={item} />;
    });

    return (
     <ul>
     {listItems}
     </ul>
    );

  }
});

It's in the Home component where the real action happens. I'll present the component next, followed by an explanation:

var Home = React.createClass({
  getInitialState: function(){
    return {
      vocabulary: [],
    }
  },

  componentDidMount: function() {
    $.get(this.props.url, function(result) {
      var words = result.words;
      if (this.isMounted()) {
        this.setState({
          vocabulary: words
        });
      }
    }.bind(this));
  },

  render: function() {
    return (
      <div>
        <ListItems items={this.state.vocabulary} />
      </div>
    );
  }
});

React.render(<Home url="http://localhost:3000/vocabulary.json" />, 
  document.getElementById('app'));

Like the previous example, you'll find a getInitialState function responsible for initializing an attribute named vocabulary. Next, you'll find the method named componentDidMount, which will be formally introduced in the later section, "Managing the Component Lifecycle". This is a native React lifecycle method which will execute only once, after the initial rendering has completed. In this case, we're using componentDidMount to retrieve the JSON file (using jQuery's $.get method). Next, the vocabulary state attribute will be set to the transformed JSON (now available as an array). It's done after confirming the component is indeed rendered, because conceivably it could have been unmounted due to for instance a network timeout. Finally, vocabulary is passed into the ListItems component and rendered accordingly.

As you can see, it's incredibly easy to retrieve and render JSON using React! This is logically a topic we'll refer to repeatedly throughout the book, so stay tuned.

Managing the Component Lifecycle

So far you've only been introduced to one component-related method, namely render(). Because you'll often want to manage other aspects of the component beyond merely rendering it, React supports several lifecycle methods. In this section I'll introduce these methods, and invite you to have a look at the React documentation for a complete breakdown.

Follow along with the code in this section by checking out the mounting_example branch of the easy_react_starter repository.

The first three lifecycle method pertain to component mounting and unmounting:

  • componentWillMount: The componentWillMount method executes immediately prior to the component being initially rendered.
  • componentDidMount: The componentDidMount method executes once immediately after the component is initially rendered. You'll typically use this method for executing AJAX requests, mutating the DOM, and adding event listeners, because when this method executes the component has been rendered and has a DOM representation available.
  • componentWillUnmount: The componentWillUnmount method executes immediately before a component is unmounted from the DOM.

The following lifecycle methods pertain to component updates:

  • componentWillReceiveProps: The componentWillReceiveProps method executes every time a component receives props, except on the component's initial rendering. You might use this method to perform some sort of calculation based on these new props and then in turn set the state for a child component.
  • componentWillUpdate: The componentWillUpdate method executes immediately prior to rendering when new props or state are received. This method does not execute the first time the component is rendered.
  • componentDidUpdate: The componentDidUpdate method executes immediately after rendering the component updates within the DOM. Like componentWillUpdate, it is not execute the first time the component is rendered.
  • shouldComponentUpdate: The shouldComponentUpdate method can be used to examine newly received props and determine whether a component should be updated accordingly. If false is returned, the component will not update. This method does not execute the first time the component is rendered.

This is definitely one aspect of React that is best served with an example. You can experiment with the following example locally using the easy_react_starter repository's mounting_example branch. You'll want to open your browser's console and carefully monitor the log messages as you interact with the interface. I'll break down the two component script here, beginning with a presentation and subsequent explanation of a component called Counter:

var Counter = React.createClass( { 

  componentWillReceiveProps: function(nextProps) {
    console.log("Receiving props!");
    console.log(nextProps);
  },

  shouldComponentUpdate: function(nextProps, nextState) {
    if (nextProps.counter == 3) {
      console.log("Not rendering this time!");
      return false;
    }
    return true;
  },

  render: function() {

    return (
      <div className="terms-counter">
        <h1>Terms Reviewed: {this.props.counter}</h1>
      </div>
    );
  }

});

This child component will render a counter which is incremented every time the user presses a button found in the below parent component. The componentWillReceiveProps method will execute every time the component receives new props, but remember it will not execute the first time the component is rendered. The shouldComponentUpdate method will also execute every time new props are passed to it, and if the new props counter value happens to be set to 3, the component will not be rendered anew.

Let's next have a look at the parent component:

var Hello = React.createClass({

  getInitialState: function(){
     return {
       count: 0
     }
  },

  componentWillMount: function() {
      console.log("About to mount the component.");
  },

  componentDidMount: function() {
    console.log("Component has been mounted. We can interact with DOM now: ");
    console.log(React.findDOMNode(this).innerHTML);
  },

  componentWillUnmount: function() {
    console.log("Component has been unmounted.");
  },

  shouldComponentUpdate: function() {
    return true;
  },

  clickHandler: function(e) {
    this.setState({
      count: this.state.count + 1
    });
      e.stopPropagation(); 
  },

  unmountComponent: function(e) {
    React.unmountComponentAtNode(document.getElementById('app')); 
  },

    render: function() {

      console.log("Component rendering.");

        return (
         <div>
         <h1>Welcome to VocabGiant</h1>
         <button type="button" onClick={this.clickHandler}>Increment</button>
         <Counter counter={this.state.count}/>
         <button type="button" onClick={this.unmountComponent}>Unmount Component</button>         
         </div>
        );
    }

});

React.render(<Hello />, document.getElementById('app'));

You'll certainly spend a lot of time interacting with a component's lifecycle, and these methods greatly reduce the amount of work you'd otherwise have to do in this regards. Be sure to spend some time experimenting with this example until you're familiar with the various methods and associated usage.

Summary

Wow, we've only completed a single chapter and you've already managed to use React to create an interface containing several components, capable of responding to user input, offering a simple real-time filtering feature, and rendering data retrieved from a JSON file! Granted the interface isn't very eye-appealing however soon enough you'll learn how to spruce it up. However, before jumping into CSS- and layout-related matters it is crucial to spend some time configuring a proper application development environment and workflow. We'll spend the next chapter doing exactly that!