Intro

Welcome to A Complete Intro to React. The goal of this workshop is to get you full up to speed on modern development and give you an idea what it is like to develop an app in the React ecosystem.

When talking about React, you cannot simply use just React. It is an incomplete picture; it is a cog in the machine. React does well to introduce some useful primitives into your toolbox and allows you to build your app without introducing too many opinions. As such, we need to learn some other tools to round the whole story of our app. However, keep in mind that these are modules we are choosing to plug together; you are free to go home and swap in your own parts to suit your own needs. While React fits many/most needs, this complete stack won’t; it has opinions and you need to make sure each piece contributes to your story and try not to shoehorn any piece in that you don’t need.

In addition to React, we are going to be using node.js, express, redux, WebPack, Mocha, Enzyme, npm, and react-router. Don’t worry if you’re aren’t familiar with any of these: that’s the point of this workshop. Since this workshop is about React, we will not be deep diving into node.js or database schema. We will discuss these satellite concepts just as they pertain to React.

Questions? Feel free to tweet at me. Corrections or concerns about this page? Please file an issue or make a pull request on the repo.

Setup

In order to be able to complete this entire workshop, we need to go ahead and get some tools downloaded. Even better if you can complete this before the workshop since conference Wi-Fi is notoriously spotty.

Clone the git repo

Click here.

node.js 6+

You probably can complete this with something less than node 4 but I’m using v6.9.1. Being the node.js LTS release, it’s a safe bet to be using. If you need to use a different version of node for work, I strongly recommend using nvm. I recommend getting the binary straight off the node website and not using homebrew for installation.

Yarn

We’re going to use Yarn for this workshop. In practice this will be a little differences to you, but what’s happening under the hood will be good for your app. Yarn will essentially replace your usage of the npm CLI client in your app. Instead of npm install --save react you’ll run yarn add react. This installs the same package from the same npm registry (it runs through their own proxy but as of writing the registry.yarnpkg.com address is just a dumb passthrough.)

If you haven’t installed yarn, install it via npm install --global yarn. You can also install it via homebrew: brew update && brew install yarn. Relevant tweet.

Yarn does a couple of things different from npm. One, it’s 100% deterministic. Deterministic is just a fancy way of saying that if you run yarn from any state, any time, 1000x times, it will still work the same way the 1001st time. npm’s installs are nondeterministic. If you run it from various states, it will install different ways.

Yarn does some better caching too. In fact, it does it so well you’ll see a significant reduction in your install times. Big code bases have seen a 10x reduction in install times.

Yarn also locks down your dependencies by default. It’s possible to do this with an npm shrinkwrap command but if you’ve ever had to maintain one of those, it can be messy. This locking down of dependencies means you don’t have to rely on npm authors doing semver correctly, a notoriously controversial subject

yarn installs

Run yarn from the directory where you downloaded the repo. If you have node and npm installed, you should see a list of dependencies being installed.

yarn global installs

Run the following global npm installs

yarn global add jest@v16.0.2
yarn global add nodemon
yarn global add webpack@v2.1.0-beta.25
yarn global add standard@v8.4.0

We’ll be using webpack v2.1.0-beta.25 (the stable version of v2 may be available by the time read this,) Jest v16.0.2 and standard v8.4.0. It doesn’t really matter version of nodemon you use. You don’t necessarily need these exact versions but you may run into issues if you use different major or minor releases as things make break between versions.

React

Welcome to the wonderful world of React. We are going to start with the most absolutely barebone version of React. No JSX. No ES6. No transpilation. Just pure component-oriented pleasure of coding.

So let’s talk about what React is. I imagine most of those who take this class will come from another framework or library, be it jQuery, Angular, Backbone, Ember, Knockout, or something else. I will draw comparisons and contrasts to these other frameworks (despite not being the same, I’ll be using the word library and framework interchangeably for brevity’s sake) to help illuminate some of the differences but you needn’t have programmed in these other frameworks to understand this workshop.

React is a library to build the views in your app. In truth, it shares more similar responsibilities to jQuery than it does to Angular or Ember: it is not a the framework but rather a component you’ll use in constructing your own framework. If you’ve done Backbone, React is just the view but not the model or component. While it can do a little data management (which is sufficient for small apps,) you really need some other construct to manage your data if you are doing some sort of app. We will get to that later using redux.

It bears mentioning that we are slowly going to build a full stack app progressively over the course of this workshop, piece-by-piece. By the end of the workshop, you’ll have built a real-time app that does streaming video.

My First Component!

So let’s start our first React code!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vidflix</title>
</head>
<body>
    <div id="app"></div>
    <script src="node_modules/react/dist/react.js"></script>
    <script src="node_modules/react-dom/dist/react-dom.js"></script>
    <script>
        var div = React.DOM.div
        var h1 = React.DOM.h1

        var MyFirstComponent = React.createClass({
          render: function () {
            return (
              div(null,
                h1(null, 'This is my first component!')
              )
            )
          }
        })

        ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))
    </script>
</body>
</html>

My Second Component

Good job! You should see the text “This is my first component!” on the screen. As you may see, we constructed a bit of DOM using functions. That’s all components are in React: functions. This ends up being a useful and powerful abstraction which you hopefully will see as we go on. This is about as simple as it gets as far as a React component goes. Let’s take it one step further by nesting some components.

Notice we are using two React methods here: createClass and createElement. createClass creates a new blueprint for an element, allowing you to create many of the same class. createElement creates a new, single instance of that blueprint. In this case we create an instance of that blueprint for the DOM. Once we start using JSX, you won’t actually need to ever use the createElement API; JSX calls it for you.

Before we start here, let’s delete that bottom script tag in index.html and add <​script src="js/ClientApp.js"></script> so we can get some good code separation going. Once done with that, create the js directory and add the ClientApp.js file. In this file, let’s put

/* global React ReactDOM */

var div = React.DOM.div
var h1 = React.DOM.h1

var MyTitle = React.createClass({
  render () {
    return (
      div(null,
        h1(null, 'Check out this component!')
      )
    )
  }
})

var MyFirstComponent = (
  div(null,
    React.createElement(MyTitle, null),
    React.createElement(MyTitle, null),
    React.createElement(MyTitle, null)
  )
)

ReactDOM.render(MyFirstComponent, document.getElementById('app'))

Cool, right!

MyTitle is a ReactComponent class. This is a constructor function that, once invoked, is expected to return a JavaScript object with at least a render method on it.

To invoke this constructor and create a new instance of the MyTitle component, you have to use the React.createElement method. The resulting instance is a ReactElement.

We can use this element the same way we use any other HTML-native tag. This allows us to encapsulate style, behavior, and markup into one neat little package and reuse these components everywhere!

To sum-up, we’re using createClass to create the component and then we’re using createElement to create an instance of that class, resulting in an element that can be used in others components.

Factories

This is a bit verbose to write React.createElement so many damn times. Let’s use a shortcut.

// replace MyFirstComponent
var MyTitleFact = React.createFactory(MyTitle)

//replace render method's body
return (
  div(null,
    MyTitleFact(null),
    MyTitleFact(null),
    MyTitleFact(null)
  )
)

We can use createFactory to side step this. Now we can use our class like we use div. In fact React.createElement('div', null) works the same as React.DOM.div. The one I showed you is just a convenience factory method that React provides for all of the HTML tags.

Props

Our title component is cute but not super reuseable. Let’s make it a bit more flexible by using some props. Props are variables that you pass from the parent to the child but the child cannot modify the props it gets. This simple restriction helps a lot in the future because when bugs arise, you know the child didn’t modify the variable because it can’t! Let’s see how to do it.

/* global React ReactDOM */

var div = React.DOM.div
var h1 = React.DOM.h1

var MyTitle = React.createClass({
  render () {
    return (
      div(null,
         h1(null, this.props.title)
      )
    )
  }
})

var MyTitleFact = React.createFactory(MyTitle)

//replace render method
var MyFirstComponent = React.createClass({
  render () {
    return (
      div(null,
        MyTitleFact({title: 'Props are great!'}),
        MyTitleFact({title: 'Use props everywhere!'}),
        MyTitleFact({title: 'Props are the best!'})
      )
    )
  }
})

ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))

Now we can change the contents of the title. But since we can pass in lots of props, we can widely differing elements of the same class based on what props are passed into the element. Let’s take it a step further (and show you how to do inline styles and attributes with React.)

// change MyTitle's inside h1
h1({ style: {color: this.props.color} }, this.props.title)

// change MyFirstComponent inside div
MyTitleFact({title: 'Props are great!', color: 'rebeccapurple'}),
MyTitleFact({title: 'Use props everywhere!', color: 'mediumaquamarine'}),
MyTitleFact({title: 'Props are the best!', color: 'peru'})

Let’s stop there and switch our attention a bit to tooling. So far we’ve been writing React with no compile step which is pretty cool and not something enough do in the course of React. Certain things will just make sense because you know what it complies to. In any case, onward!

Tooling – standard and npm

Before we can introduce JSX to React, we are going to have to send it through a compilation step. So we are going to take a brief repose from React here to start working on our tooling a bit.

standard

Let’s start with the easiest to start with right now: standard.

standard is a linting tool. Specifically, the executable version of standard that you get when you yarn global add standard is a wrapper around a pre-configured eslint. If you are unfamiliar with linting tools (like jshint, jslint, jscs) the basic gist is that this tool programatically checks for certain violations of code style in your code. A common (and arguably the most useful) check that it does is make sure you have no unused variables and that you make use of no undeclared variables in your code. A common reason to trip either of those rules is that misspelled a variable somewhere. There are dozens of other checks standard does: check them out here.

A note on standard, since it inevitably causes controversy. standard is a set of eslint rules that is meant to not to be configurable to totally sidestep the conversation of what rules to include and what not to. It’s meant to be a step in the direction of a standard format in the JavaScript community, much akin to how the Go community has standardized on one. Perhaps the most controversial rule in standard is no semicolons. It’s okay to not use semicolons in JS. Really. I promise. It’s not slower and it won’t introduce crazy bugs. It’s okay to use them too! It doesn’t particularly matter. However, in this workshop, you code won’t pass lint if you use semicolons. If you insist that you need your semicolons, you can use the package semistandard. But give standard a shot. You may like it.

That being said, we will introducing new rules for our JSX since we want some rules added to enforce good “Reactful” code.

So, head to your terminal and navigate to the directory of the project. Given that standard is preconfigured to recursively check all js and jsx files recursively in a project and leave out some sane defaults (it doesn’t check node_modules/) you should be able to just run standard from your terminal and see if you have any issues. If you do, go fix them! If you feel so inclined, you can use standard-format to have your code auto-fixed for you. I’ve found it sometimes has some derpy indentation but you may have better results.

npm scripts

One of the nice convenience that npm allows you is its scripts features. If you work on a team or an open source project, it’s a great way to standardize how things are done in your project. Even if it’s just you, it’s an easy way to shorten commands. So go to your package.json and add:

"scripts": {
    "lint": "standard"
},

Once in your package.json, now you can go to your terminal and run npm run lint and it will run standard for you. This isn’t a big right now but we’ll start chaining our whole testing process together and we won’t have to remember the complex stuff we’re doing each time. We’ll have several scripts in here and it quickly becomes very convenient.

Since all our tests, lints, and builds will be done through npm scripts (which are just commands piped to the terminal) we don’t need any tools like Grunt, Gulp, or the like. Anyone who has ever maintained a Gruntfile knows why this is such a big deal. Not to disparage task running tools though; if you have a complex build they quickly are worth their weight in gold. Our builds will be simple and so a simple tool serves nicely.

Tooling - Webpack and Babel

Now that we have clean code via a linter and can run our scripts courtesy of npm, let’s work on the compilation / build of our code. In order to achieve this we are going to use two tools: Webpack and Babel.

Webpack

Webpack is an amazing tool that came out two or so years ago that captivated particularly the React crowd quick due to its ease and interesting features. We are going to only scratch the service of this powerful tool; you could give a whole workshop just on Webpack. We are going to lean on two of Webpack’s core features: module compilation and the ability to plug in loaders.

As you saw with our code, it is pretty easy to put one or two components in one file. But what happens when you have an app as complex at Netflix that has hundreds, if not thousands, of components? Having just one file is untenable. You could just split them into separate files, make sure to load them in correct order, and keep a list of files in your HTML directory. But that sucks too, so we’re going to introduce a build step that, while build steps suck, this will make things a bit easier.

For fun, split your MyTitle component from ClientApp.js into a new file, MyTitle.js. You will have to put the appropriate React.DOM helper methods in each file. At the bottom of MyTitle.js, add the line module.exports = MyTitle. At the top of ClientApp.js, put the line var MyTitle = require('./MyTitle'). Let’s try to compile that.

You should have Webpack 2.1+ installed. Go to the directory of the project in the terminal and run mkdir public. After that, run webpack js/ClientApp.js public/bundle.js. In your index.html, change the line of <​script src="js/ClientApp.js"></script> to <​script src="/public/bundle.js"></script>.

Try your browser again. bundle.js has all the stuff for both files now. Now we can keep components in their own files which is a huge win for organization. But wait, we can use Webpack for even greater code by using it to bring in node modules. In index.html, remove the other script tags so just bundle.js is left.

In ClientApp.js, remove the global comment at the top and add at the top

import React from 'react'
import { render } from ('react-dom')

// change render
render(React.createElement(MyFirstComponent), document.getElementById('app'))

In MyTitle, add:

// remove global comment, add at top
import React from 'react'

// add to bottom
export default MyTitle

Run your Webpack command again. Try your browser again. Despite only including bundle.js, the whole app works! If you look at Webpack, you’ll see it’s 99% React code and some of yours. Now we can go forth making new files and including new libraries without worrying about if they are being included!

Let’s add build to our npm scripts. Add to scripts in package.json "build": "Webpack js/ClientApp.js public/bundle.js",. Run npm run build from your terminal in the project root directory and see if it works. Magic!

We’re also using ES6 modules here, if you’re not familiar with that syntax. The import React from 'react' is semantically identical to var React = require('react'). The import { render } from 'react-dom' as far as you’re concerned here is identical to var render = require('react-dom').render. For further reading, checkout 2ality’s post on it.

Babel

Babel is an amazing, amazing tool that has fundamentally altered the landscape of JavaScript as we know. Though they didn’t invent the idea of transpiling future syntax of JavaScript into current syntax (thanks Traceur,) they did make it so damn easy. Couple that with the fact it worked with React’s JSX (which we’ll talk about in a sec) and it was a perfect storm the be massively successful. Babel, in short, is amazing and should be something you consider for every project.

Babel 6 (the latest revision of Babel) took away a tiny bit of that ease of use but in return it became much easier to develop which is important when you’re maintaining a massive project that’s very important. In return it requires a bit of config now.

Create a new file called .babelrc. Inside .babelrc, put:

{
  "presets": [
    "react",
    ["es2015", {"modules": false}]
  ]
}

Babel has the concept of plugins. Each transformation comes in the form a plugin. However ES6 and React each have a number of transformation and it’s a huge pain to include each one. Thus Babel has the concept of presets, or in other words bundles of plugins. In this case, we’re including all of the React and ES6 transformations. If this were a production app we would definitely go through and only include the transformations we needed and not all of them. For example, this includes a fairly large library to get ES6 generators working. Few people these days are actually using generators and thus it’s better to leave them off if you don’t need them. In our case, this is a teaching app so page weight isn’t a big deal to us. This will also allow us to start using JSX.

Also, we’re telling Babel to not transform modules. New to Webpack 2 is the ability to do tree shaking. Tree shaking (also known as live code inclusion, as opposed to dead code elimination) is where you start with the entry point to your program (usually an index.js) and begin working outwards, only including the parts of code your code uses. Usually this doesn’t buy you much in terms of your code; we tend to not write much dead code for our apps. However it’s extremely helpful for modules you’re including. If you use lodash for one function, you don’t want to include the whole library. Instead, you want your bundler to just include that barebones of what you need for to work. This is what Webpack 2 and Uglify buy for us; Webpack 2 bundles and Uglify takes the dead code paths out.

Webpack loaders

So, we could use the Babel CLI to compile our code but we are already using Webpack and Webpack has a good way to send your code through Babel via its loader mechanism. Loaders are utilities that Webpack will pipe input into and accept output out of. You can use loaders to transpile things like CoffeeScript, TypeScript, or PureScript. Webpack loaders can do some other powerful things like allowing you to include CSS, inline images via encoding, and transform SVGs. We’re just going to be using the JS transformation abilities for now. Run the command webpack --module-bind 'js=babel' js/ClientApp.js public/bundle.js. Should take a bit longer since it’s doing more. Since we’re going to be using Webpack for a few other things, let’s abstract that configuration from inline to a config file. Add a webpack.config.js with the following.

const path = require('path')

module.exports = {
  context: __dirname,
  entry: './js/ClientApp.js',
  devtool: 'source-map',
  output: {
    path: path.join(__dirname, '/public'),
    filename: 'bundle.js'
  },
  resolve: {
    extensions: ['.js', '.json']
  },
  stats: {
    colors: true,
    reasons: true,
    chunks: false
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader'
      }
    ]
  }
}

What you see is essentially a config version of what we were doing with CLI flags. Now it’s a bit more resilient and guaranteed consistent. If you run just the command webpack from your project directory you should get the same output. Neat. Go change you npm script to just be “webpack” now. Go try it and make sure it still works. Great! Also make sure all the files you’ve written are still up to snuff with standard via npm run lint. Good? Good. This should get us to a point now where we can talk about JSX.

JSX

We have been writing our React with vanilla JavaScript up until now which frankly few people do. Most people take advantage of JSX which essentially adds HTML/XML-like syntax as a “primitive” type to JavaScript. In reality, what it does it takes the HTML you write for your components and translate them into the same calls we writing just using vanilla JavaScript.

So why JSX? People usually get pretty grossed out by the HTML in the JavaScript and say it looks like 1998 when we were still writing JavaScript in our HTML. However, I assert that markup in JS is a good thing while JS in markup is a bad thing! Here, we’re keeping all the concerns of a component in one place: the markup structure, the event listeners, the state, the state mutators, everything. If the component breaks, we know it broke there. That’s really valuable.

So try it. While the plain JS way isn’t too bad, once you start writing JSX I almost guarantee you won’t want to go back. Let’s convert what we have to JSX.

Side note: good idea to install a JSX syntax highlighter. If you’re using Sublime, I highly recommend the “Babel” package off of Package Control. If you’re using VIM, try VimBox. I have no experience with it but I’ve heard it helps.

import React from 'react'
const div = React.DOM.div
const h1 = React.DOM.h1

const MyTitle = React.createClass({
  render () {
    const style = {color: this.props.color}
    return (
      <div>
        <h1 style={ style }>
          {this.props.title}
        </h1>
      </div>
    )
  }
})

export default MyTitle

We’re using JSX finally! Make sure you’re inserting those opening and closing parens around the component. It’s just letting JS know you’re going to put your expression on the next line (which we want to do for readability.)

Notice the curly braces surrounding this.props.title. They’re there to let JSX know I want his to be a JS expression. If they weren’t there, it would literally put the string ‘this.props.title’. Notice the double curly braces surrounding the style value. The exterior set of curly braces are the same as the one as before: they’re letting JSX know you want a JS expression. The interior set of curly braces represent a JavaScript object, meaning you’re passing in a object to the style attribute. A little strange to get used to seeing that.

Lastly, you may notice that I switched to an ES6 style here. This is synonymous with the function syntax; just a bit more terse. Feel free to write it in any syntax that fits your fancy; this is very readable to me but may not be to you. Basically, since it’s an arrow function and lacks curly braces, the resulting component is implicitly returned automatically.

Let’s rewrite ClientApp.js.

const React = require('react')
const ReactDOM = require('react-dom')
const MyTitle = require('./MyTitle')

const MyFirstComponent = React.createClass({
  render () {
    return (
      <div>
        <MyTitle title='Props are great!' color='rebeccapurple' />
        <MyTitle title='Use props everywhere!' color='mediumaquamarine' />
        <MyTitle title='Props are the best!' color='peru' />
      </div>
    )
  }
})

ReactDOM.render(<MyFirstComponent/>, document.getElementById('app'))

Also make sure you update your webpack.config.js to point the JSX path of ClientApp.js on the entry line.

Notice how we use our own components as if they were normal HTML tags. Neat, right? We define our own components and then we can throw anywhere since they’re self contained! We even pass them props as if they were normal attributes.

Also notice we’re including React in both files but not directly manipulating it. This is okay since remember JSX is converting these tags to calls to React, so in reality it is using React (and thus we do have to include it.) We dropped the createFactory business. No longer useful since JSX is totally fine to convert our JSX to the long-form function call. Overall a simplification I think!

Something to make note of: the top level component has to be singular, or in other words, your top level component cannot be sibling to something else. This makes sense if you think about what JSX is transpiling to: function calls.

// won't compile
const InvalidComponent = () => (
  <h1>My Title</h1>
  <h2>My Title 2</h2>
);

// will compile
const ValidComponent = () => (
  <div>
    <h1>My Title</h1>
    <h2>My Title 2</h2>
  </div>
);

Hence why you’ll see a lot of wrapping divs in JSX; it’s so the whole thing will compile. This is fine if you need to do this; an extra wrapping div does nothing of harm unless you have structurally sensitive CSS. Also notice that if you have just raw text to put into JSX, you can enter it just as if was normal HTML. It’s only when you have JS expressions when you need to use the curly braces.

More React

So let’s actually discuss what we’re going to build today: a basic Netflix experience. This is going to afford us several fun experiences and use cases to explore with our new-found stack. Our app is going to have a home page, a browse/search page, and a video page. Over the next few chapters we are going to be talking about redux and react-router and their rather-central roles to the React eco-system. But first let’s keep diving into React.

Rather our toys we’ve made so far to demonstrate how to make React components, let’s actually start building our web app. We are going to make our home page. The home page is going to have a sweet background image, our logo, a text input to search for a specific show, and another button to just browse all videos.

I have pre-done all the CSS for you (since this is not a workshop on CSS) so if you just follow my CSS naming you will get all the CSS for free. It does bear mentioning here that libraries like Radium or Aphrodite exist that allow you to do all of your styles in JS and let React and Radium handle all the styles for you. This is a pretty big departure from normal web development and not something most developers do so we’re not going to cover it. But I will say, should you feel so inclined, go out and give it a shot. I did for a little side project and had a blast with it; it’s a fun way to approach CSS since you have all the tools of JS at your disposal and don’t really have to care how it compiles down to CSS like you do with PostCSS/Sass/less. Anyway, follow my CSS and you’ll be golden. If at any time your styles look broken as compared to mine, chances are you misnamed something or misstructured the tags.

We are going to do our CSS via imports though, which is pretty fun. I’ve seen people make a 1-to-1 mapping of CSS file to JS file and that makes a lot of sense to me; here we’re just going to scratch the surface by showing you how to import two CSS files and then after that you’re on your own to explore. Add the following to your loaders array in webpack:

// in your rules array
{
  test: /\.css$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        url: false
      }
    }
  ]
},

We need two loaders to load: the CSS loader and the style loader. The CSS loader basically lets Webpack understand CSS; without it Webpack doesn’t speak/parse CSS. It doesn’t do anything at this point with it though. You could just as easy put the Less or PostCSS loaders instead of the CSS loader if you wanted to have an augmented CSS language to work with. The style loader takes the finished, parsed CSS and then bundles that into your JS bundle. So you do need both but I wanted you to understand why they’re separate.

The url: false option for the CSS loader is so that the CSS loader doesn’t attempt to bundle your images into your JS bundle too; by default it will try to read the images from the CSS and bundle it into your JS. I happen to think this is a bad idea and thus opt out of it; if you leave it in there you’ll need another loader capable of reading images, base64 encoding it, and bundling that into your package too.

Let’s start building our app. You can delete MyTitle.js if you desire; you can also leave it. We’re not going to be using it any further. Go ahead and clear out most ClientApp.js and let’s start putting our app in here.

Oh, and you also have to name your video service. I named mine svideo but name your app whatever you want!

Right now it’s going to be pretty simple. Drop in this:

import React from 'react'
import { render } from 'react-dom'
import '../public/normalize.css'
import '../public/style.css'
const App = React.createClass({
  render () {
    return (
      <div className='app'>
        <div className='landing'>
          <h1>svideo</h1>
          <input type='text' placeholder='Search' />
          <a>or Browse All</a>
        </div>
      </div>
    )
  }
})

render(<App />, document.getElementById('app'))

Save and run npm run dev. If you followed the CSS naming and HTML structure, you should see a nice looking landing page. Also a good time to make sure if your code is still lint-compliant.

So, another tooling detour here: I’m getting pretty sick of having to hit the terminal every single time to see run build. Furthermore, build for webpack is pretty slow despite how small our code is. So let’s take advantage of webpack’s watch feature. This will watch for every time you save rebuild automatically. Additionally it will keep the unchanged bits (like the React library) in memory so it doesn’t have to rebuild it every time. Try running webpack --watch in your terminal. It will use the same config we already made. See how much faster it is after running? Let’s add a new npm script.

// in package.json in scripts
"watch": "webpack --watch",

Great, right? So, another part that’s been bothering me is that it’s such a pain to have to re-run standard every time. Either that or you’ll get a bunch of errors all at once when you run it before you commit. Luckily we can have webpack run standard each time it compiles. It will then notify you when you have errors.

Just like we’re using the babel-loader to transpile our code, we’re going to use the eslint-loader to run standard for us. eslint is what standard uses under the hood, or in other words standard is just a specific configuration of eslint. We’re going to lean on this fact and use a config file with the eslint-loader.

Create a file called .eslintrc.json. That first period is significant. Inside the new file put:

{
  "extends": ["standard", "standard-react"]
}

This will configure eslint to check for everything standard has been checking. In addition, since we’re already adding a config file, we’re adding a few checks specific to React and JSX. Again, these will spare you bugs in the future and they’re super helpful. Let’s change our webpack config to use our new eslint-loader. eslint will automatically use our .eslintrc.json, regardless is called via the CLI or programmatically via webpack.

// inside module, before babel-loader
loaders: [
  {
    enforce: "pre",
    test: /\.js$/,
    loader: "eslint-loader",
    exclude: /node_modules/
  }
],

Nice! Any time you save now using npm run watch it will both compile your code and lint it. Pretty slick. And it all runs so much faster. We’re going to get to how to make your code reloads even faster. We do the enforce: pre part to make sure that the lint part is loaded before the build step, ensuring our uncompiled code (and not the intermediary) is always the one being linted.

Also, let’s fix npm run lint so it runs our new JSX rules. Change the package.json value for lint to be eslint js/**/*.js. Don’t worry if you don’t have eslint installed globally; the npm CLI is smart enough to look in your node_modules to find it (where we already installed it.) This will run all the code with the js extension in the JS directory through ESLint. It will use the config that we made earlier. The ** means go recursively deep into the directory; otherwise it’ll just do the top level.

Now let’s switch to the Webpack dev server which makes things just that much easier. The Webpack dev server speeds up development by letting you run a local server and serve all your content from the dev server. It watches and keeps everything in memory so rebuilds go faster. Add the following to your server to get it to serve your statics correctly:

// add as a top level config item
devServer: {
  publicPath: '/public/'
},

Now try running this from the directory of your project: ./node_modules/webpack-dev-server/bin/webpack-dev-server.js. You could install this globally but we’ll use npm’s cli to make this easy. You should see in your CLI a bunch output from the build and probably some linter errors. Feel free to fix your errors but now you should be able to go http://localhost:8080 to see your project running. You should also see the build output in the console of the browser. Cool! Add the following line to your npm scripts: "dev": "webpack-dev-server",. Now you can do npm run dev and your code will start building and serving right away!

But first let’s keep going with our app. Our landing is pretty much done for now. We want to start working on the browse all page, but we need to move onto the router to do that real quick.

React Router

So now we have a basic landing page and we want to be able to transition to another page. Because we making this as a single page app, we are going to use the marvelous react-router. react-router is a robust piece of technology and we are just going to be scratching the surface of it now. If you intend on making a single page app, I suggest you deep dive into it to uncover all of its potential.

We’re going to be using React Router version 4 here. This is significant because React Router has gone through several thrashes of API, from 0 to 1, from 1 to 2/3, and now from 2/3 to 4. The authors have assured us that this is the last major thrash but it quite a departure, but thankfully the thrash is worth it. It got a lot easier to use.

We are just use the top level router at the moment. First, let’s move our landing page into its own component so we can use ClientApp as the entry point for the app. Move all the code (except the ReactDOM last line; leave that there) to Landing.js.

// Landing.js
import React from 'react'
import '../public/normalize.css'
import '../public/style.css'

const Landing = React.createClass({
  render () {
    return (
      <div className='landing'>
        <h1>svideo</h1>
        <input type='text' placeholder='Search' />
        <a>or Browse All</a>
      </div>
    )
  }
})

export default Landing
// ClientApp.js
import React from 'react'
import { render } from 'react-dom'
import { BrowserRouter, Match } from 'react-router'
import Landing from './Landing'

const App = React.createClass({
  render () {
    return (
      <HashRouter>
        <div className='app'>
          <Match exactly pattern='/' component={Landing} />
        </div>
      </HashRouter>
    )
  }
})

render(<App />, document.getElementById('app'))

Cool. Make sure standard isn’t yelling at you and that your app still works. It should appear pretty much the same to you. The HashRouter is a sort of hacky router which puts your route information into the hash of the URL (after the #). We’ll use BrowserRouter later so we have nice URLs, but for now this gets us started. The Match component is a route; when it matchs the pattern provided (in this case we don’t want fuzzy matching, hence the exactly attribute) it render the component provided, in this case the Landing component. It’s wrapped in a div because routers can only have one child since they render them directly, but it’s nice because all routes will now get the styling from the .app class for free.

Now we have a router so we’re free to introduce a second page! Let’s make our search page. Create a new file called Search.js. In Search.js put:

import React from 'react'

const Search = React.createClass({
  render () {
    return (
      <h1>Search!!</h1>
    )
  }
})

export default Search

Put in ClientApp

import React from 'react'
import { render } from 'react-dom'
import { HashRouter, Match } from 'react-router'
import Landing from './Landing'
import Search from './Search'

const App = React.createClass({
  render () {
    return (
        <HashRouter>
          <div className='app'>
            <Match exactly pattern='/' component={Landing} />
            <Match pattern='/search' component={Search} />
          </div>
        </HashRouter>
    )
  }
})

render(<App />, document.getElementById('app'))

In Landing, change the or Browse All to

// add at top with other requires
import { Link } from 'react-router'

// change <a> to
<Link to='/search' className='browse-all'>or Browse All</Link>

Now you have another working route (which all it’s doing is showing an h1) and a link to get there. When linking between routes with react-router, use the Link component. This allows you to refactor how routes work without having refactor all of your individual links (you could just make your a’s href “#/search” and it would work for now but could break later.) Now your button should work to take you to the browser page and you should be able to use back and forward for free thanks to react-router.

The HashRouter sort of sucks though so let’s migrate to BrowserRouter. First, we have to make webpack-dev-server aware that it should pass unfound routes back to index.html anyway. Add the following line your webpack.config.js inside of the devServer object: historyApiFallback: true.

Then go to ClientApp.js and change all references (the import and the use of the component) of HashRouter to BrowserRouter. Now instead of #/search, it should go to just /search. Yay!

React: Props

Let’s start making our search page. We’re going to start with some dummy data and work our way from there. Again, follow the same HTML structure and CSS naming as me and you’ll get all the styling for free. Feel free to take a glance at public/data.json to see what’s there. As you may have guessed, it’s a bunch of Netflix shows. This whole workshop is actually just an elaborate advertisement for Netflix (just kidding; I promise.)

Webpack allows you to require in json files just like you would another JavaScript file so we’ll take advantage of that when we start coding our new search page. However we do have add another loader to do that. Add the following object to your loaders array in your webpack.config.js.

  {
    test: /\.json$/,
    loader: 'json-loader'
  }
// in replace Search.js
import React from 'react'
import preload from '../public/data.json'

const Search = React.createClass({
  render () {
    return (
      <div className='search'>
        <pre><code>{JSON.stringify(preload, null, 4)}</code></pre>
      </div>
    )
  }
})

export default Search

You should see it say dump a lot of JSON to the page at the top of the page. When you use curly braces in JSX, you’re telling JSX you want it run a JavaScript expression and then display whatever it returns. If you take away those curly braces (try it) you’ll see it literally displays “JSON.stringify(preload, null, 4)” as a string. So that’s a neat tool to have; let’s take it a step further and display all of the titles as their own components.

As you may remember, JSX is transpiling your JSX-HTML to function calls. As such, you may be able to imagine that a bunch of sibling components are just an array of components. Since they’re just normal ol’ JavaScript arrays, we can use some functional-programming-fu to transform data into components.

// replace render's return
<div className='search'>
  {preload.shows.map((show) => {
    return (
      <h3>{show.title}</h3>
    )
  })}
</div>

You should now see all of the titles in a nice scrollable list. This is the ng-repeat/#each of React: plain ol’ JavaScript map. If you are not familiar with map, read this. This is one of the reasons I love React: for the most part best practices of React are just JavaScript best practices. There’s very little DSL to learn. Cool! Let’s flesh out how our search results are going to look.

import React from 'react'
import preload from '../public/data.json'

const Search = React.createClass({
  render () {
    return (
      <div className='search'>
        <div>
          {preload.shows.map((show) => {
            return (
              <div className='show-card'>
                <img src={`/public/img/posters/${show.poster}`} />
                <div>
                  <h3>{show.title}</h3>
                  <h4>({show.year})</h4>
                  <p>{show.description}</p>
                </div>
              </div>
            )
          })}
        </div>
      </div>
    )
  }
})

export default Search

Try saving and re-rendering. You should see some nice cards for the shows. Notice that we can use those fancy curly braces to insert JavaScript expressions into HTML attribute too. Neat.

However we can reorganize this a bit better: the ShowCard component can be broken out into its own component. Let’s do that. Make a file called ShowCard.js and put this in there:

import React from 'react'

const ShowCard = React.createClass({
  render () {
    return (
      <div className='show-card'>
        <img src={`/public/img/posters/${this.props.show.poster}`} />
        <div>
          <h3>{this.props.show.title}</h3>
          <h4>({this.props.show.year})</h4>
          <p>{this.props.show.description}</p>
        </div>
      </div>
    )
  }
})

export default ShowCard

Notice we’re using this strange props object that’s coming from this context. This is what we are going to be receiving from our parents. In this case, an individual ShowCard needs to receive all the necessary data from its parent to be able to display it.

This is a good time to discuss the philosophy that’s sort of tough to get used to with React coding. We typically think of user interfaces as entities that change over a span of actions and events. Think of a jQuery UI you have made. Imagine making a drop down. You would have to write the code for a user clicking it to opening the drop down to the user clicking an item in the drop down. It’s a progression of time, events, and interactions. Imagine if there was a bug with that final interaction. You now have to work out in your head the sequence of events to get it to that same state that the bug occurs in to able to fix it. This is second nature to many of us since we have done it so many times.

React takes a fundamentally different approach but it takes some retraining of your brain. However I argue this approach is superior due to it being much easier to reason about, making it more readable for newcomers to the code and much more debuggable. In React, you think of your UI as snapshots. You do not think of it as a progression of time and events; rather, you look at the UI as how is it going to look given a set of parameters. That’s all it is. Given a set of parameters, how does this UI look? Using the drop down example, you think of the drop down in its various states: an open state, a closed state, and an event that triggers when you click the item. You represent these varying states using props and state (we’ll get to state in a bit.) Given a certain set of props, the UI always looks this way. This will become more concrete as we go on.

This brings me to my next point: when coding React, assume you have all the data you need coming in via props and then figure out later how to get it there. That will make it much easier. Just assume it all works and then later go make it work.

And these principles? Not invented by React. These are battle-tested ideas that stem a lot from functional programming. There’s a lot of good computer science going on here, whether or not we use React to apply these concepts.

Okay, great, let’s go to Search and drop in our new component.

import React from 'react'
import ShowCard from './ShowCard'
import preload from '../public/data.json'

const Search = React.createClass({
  render () {
    return (
      <div className='search'>
        <div>
          {preload.shows.map((show) => {
            return (
              <ShowCard show={show} />
            )
          })}
        </div>
      </div>
    )
  }
})

export default Search

Much like you give an HTML tag an attribute is how you give props to children components in React. Here we’re passing down an object to our child component to make it available to the ShowCard via props. Neat, right? Save it and reload the page. standard is going to give you a bunch of complaints but we’re going to address that momentarily. You should see the same UI.

One of the errors you’ll notice in the browser console is something like: “Warning: Each child in an array or iterator should have a unique “key” prop. Check the render method of Search.” You see this because we have multiple, similiar sibling components next to each other and React doesn’t have a quick way to tell them apart. If you start reordering them (like if we added a sort feature) then React would just destroy and re-create them each time since it doesn’t know you’re just reordering them. This is unnecessarily expensive, as you may imagine. You can give React a shortcut to be able to tell them quickly apart: give each a component a unique identifier as a key attribute. So go add it to the ShowCard component like so: <ShowCard show={show} key={show.imdbID} />.

So let’s fix our standard errors now. standard-react dictates that all props have a propType. React has a features that allows you to set propTypes which it then validates at runtime. This ends up being great for debugging because React now knows what type of props it should be getting so it can give you a meaningful error messages if there’s a type mismatch or omission. So let’s go fix the errors.

In ShowCard, go add this just below the declaration of the ShowCard function:

// add below import React

// top level property in ShowCard's React.createClass object
propTypes: {
  show: shape({
    poster: string,
    title: string,
    year: string,
    description: string
  })
},

Now React knows to expect that show is both an object full of strings and those strings are required for the ShowCard to work. If a prop is optional (which is fine if it is indeed optional) then leave off the isRequired part.

We can make this a little neater via the ES6/JSX spread operator. Let’s try that. Change Search’s ShowCard from <ShowCard show={show} /> to <ShowCard {...show} key={show.imdbID} />. This will take all the properties from show and spread them out as individual properties on ShowCard. You could write <ShowCard title={show.title} poster={show.poster} description={show.description} year={show.year} /> but that’s a lot of writing and this cuts an easy corner. Let’s go modify ShowCard to match.

import React from 'react'
const {string} = React.PropTypes

const ShowCard = React.createClass({
  propTypes: {
    poster: string.isRequired,
    title: string.isRequired,
    year: string.isRequired,
    description: string.isRequired
  },
  render () {
    return (
      <div className='show-card'>
        <img src={`/public/img/posters/${this.props.poster}`} />
        <div>
          <h3>{this.props.title}</h3>
          <h4>({this.props.year})</h4>
          <p>{this.props.description}</p>
        </div>
      </div>
    )
  }
})

export default ShowCard

We’ve now made our code a bit cleaner since we don’t have to props.show… ad nauseam. I should mention that if you go down the path of Flow or TypeScriptts you don’t really need propTypes as much since the static checkers accomplish that and more for you.

React: State

We’ve discussed props which all you to have immutable state passed from parents to children. However, as any seasoned UI developer will point out, user interfaces are inherently stateful. You app at some level must contain some level of mutability. React gives you a very controlled window to introduce this mutability to be able to reason easily about this mutability aptly called state.

While props are passed down from parents and are immutable, state is created, read, and mutated all inside of a component. In other words, if a component has state, that state cannot be mutated by a parent, child, or any other external influence; only that same component has access to the setState method which is the only way to mutate state. That component has the ability to expose methods to children that the child can call to let the parent know it should mutate its state, but again, it is totally up to the parent to respect that call and mutate the state; the child can only call methods exposed to it via passed-down props.

So let’s see this in action. We’re going to add a header that allows us to search our shows.

In Search.js, add the following:

// inside div.search, above and sibling to the div that contains the shows
<header>
  <h1>svideo</h1>
  <input type='text' placeholder='Search' />
</header>

Now the UI is in place. Let’s start tracking what’s actually in the input.

import React from 'react'
import ShowCard from './ShowCard'
import preload from '../public/data.json'

const Search = React.createClass({
  getInitialState () {
    return {
      searchTerm: 'this is the default searchTerm'
    }
  },
  render () {
    return (
      <div className='search'>
        <header>
          <h1>{this.state.searchTerm}</h1>
          <input type='text' placeholder='Search' />
        </header>
        <div>
          {preload.shows.map((show) => {
            return (
              <ShowCard {...show} key={show.imdbID} />
            )
          })}
        </div>
      </div>
    )
  }
})

export default Search

I replaced the brand momentarily so you can see the see the searchTerm change. You should see whatever you made the initial state for searchTerm show up as the brand. Neat, right? Alright, let’s make it mutable now. Change the input in the header to be this:

<input type='text' placeholder='Search' value={this.state.searchTerm} />

Cool! Now your input should have the initial state of your searchTerm. Now try and type and/or delete anything. You can’t! You broke the Internet! Just kidding. But to understand why this weird bug is happening you have to understand how React handles keypresses. Your state object on your component states that the value of searchTerm is 'this is the default searchTerm'. When a keypress happens, React kicks off a re-render. Since nothing modified the value of searchTerm, it’s still the same string and thus it re-renders the same string there. Your state object is the source of truth. So let’s make the value of searchTerm bound to the value of the input.

// add method
handleSearchTermChange (event) {
  this.setState({ searchTerm: event.target.value })
},

// replace input
<input type='text' placeholder='Search' value={this.state.searchTerm} onChange={this.handleSearchTermChange} />

Now try typing in the input. As you see, the title is now reflective of whatever you type in the search input. So let’s chat about what we did here. We made an event listener that handles the change events that the input throws off when it has a keypress. That event listener accepts an event that’s technically a React synthetic event but its API looks just like a normal DOM event. In the event listener, we call this.setState, a method that allows you to mutate the state and then lets React re-render. If you don’t call setState and instead mutate this.state yourself, React isn’t privy to the fact the fact that you’re changing stuff and thus doesn’t know to re-render. In other words, never modify this.state directly and always just use setState. setState works like Object.assign in that it will do a merge of your objects (it’s a shallow merge and not a deep merge) so you’re free to just modify the keys you need to.

So go back now and change the brand to the correct title.

Let’s make the search actually do something now. Since now we have our state being tracked, let’s use it do a real time search on our titles.

// replace div inside search which contains shows
<div>
  {data.shows
    .filter((show) => `${show.title} ${show.description}`.toUpperCase().indexOf(this.state.searchTerm.toUpperCase()) >= 0)
    .map((show, index) => (
      <ShowCard {...show} key={index} id={index} />
  ))}
</div>

This is a little clever but let’s dissect the new filter line we added. We’re looking at both the title and description lines to search on and using the indexOf method from strings to see if the searchTerm exists within the description or title. We use toUpperCase on both to make it case agnostic. And the filter method on arrays just filters out items in an array that the method returns false on. Now try typing in your searchBox. You should see it filter as you type. We could make this more efficient but I’ll leave that to you in your own time.

If you’re unfamiliar with filter, check this out. If you’re unfamiliar with arrow functions, check this out. If you’re unfamiliar with indexOf, look here. And finally, for template strings (the back ticks instead of the quotes for the strings) look here.

Testing React with Jest, Snapshots, and Enzyme

Note: This is using Jest. If you want to see how to test React components using Mocha, Chai, Sinon, and Enzyme, see the previous version of this workshop.

Now that we have something worth testing, let’s test it. We’re going to be using Facebook’s Jest (v15.1.1) to do it since it has some neat features. Go ahead and add the following to your npm scripts: "test": "jest". Then go to your JS directory and create a file called Search.spec.js. I like to make my tests live right along side the files they test but I’m okay putting them in another directory: up to you. In either case Jest is smart enough to autodiscover them if you make the extension *.spec.js.

In Search.spec.js, put:

import React from 'react'
import Search from './Search'
import renderer from 'react-test-renderer'

test('Search should search titles', () => {
  const component = renderer.create(<Search />)
  let tree = component.toJSON()
  expect(tree).toMatchSnapshot()
})

This is a snapshot test and it’s a super cool new feature of Jest. Jest is going to render out the component you tell it to and dump the state of that to a file. It’s basically a free unit test that the computer generates for you. If the markup changes in the future unexpectedly, your unit test will fail and you’ll see why it failed.

So then you may ask, “What happens if I update the component on purpose?” Easy! You run the test again with the -u flag and it will write out new snapshots. Awesome! Also note you’re supposed to commit snapshots to git.

Okay, so go the CLI and run npm t (which is just short for npm run test or npm test, they all work the same.) You’re going to get some error about import being a bad token; this is true since as of Node.js 7, V8 (the JS engine that power Node.js) still doesn’t understand ES6 modules, but we still want to use them in dev so we need to do some special Babel transformations just for testing. Go to your .babelrc file and put this:

{
  "presets": [
    "react",
    ["es2015", {modules: false}]
  ],
  "env": {
    "test": {
      "plugins": ["transform-es2015-modules-commonjs"]
    }
  }
}

This will add the correct Babel transformation when you are the test environment. Now let’s make it so the jest command is run in the test environment (since by default it won’t). Go back and change your line in your npm scripts to be "test": "NODE_ENV=test jest". Now it will apply that extra transformation for you. Now try running npm t again and see what happens. If it still fails on the import token, run npm t -- --no-cache. The double dash means you want to pass parameters to whatever npm is running, in this case jest, so the command you’re actually running is jest --no-cache. That’s a useful trick to know. Then Jest likes to cache Babel transformations for ones it’s already done so that you don’t have to do it every time; this greatly speeds up running tests but it also doesn’t check to see if you updated your .babelrc. So here we need to tell it to do so.

So now that you have a passing test, try modifiying Search and running it again. It’ll give you a git diff type output and you can see what changed. If it’s what you expect, you just re-run the command with -u at the end, npm t -- -u. Let’s actually put that as an npm script so we don’t have to remember that. Add "update-test": "npm run test -- -u" to your npm scripts in package.json.

Okay, so now we have a few problems with this test. First, if we modify ShowCard, it’s going to fail this test, and I think that’s a problem. As much as possible, we want a Search test to only fail if something in Search breaks, and we want ShowCard to fail if ShowCard breaks. Luckily we can do that with a tool called Enzyme from Airbnb and a helper tool called enzyme-to-json meant to connect Enzyme and Jest’s snapshot testing. I show you both so you can see the easiest, more standard of doing snapshot testing (with react-test-renderer) and the less standard but I suggest superior way of using enzyme-to-json. Also, react-test-renderer and Enzyme can’t be imported into the same file and we need to use Enzyme for other tests later.

So modifiy your test to read:

import React from 'react'
import Search from './Search'
import { shallow } from 'enzyme'
import { shallowToJson } from 'enzyme-to-json'

test('Search render correctly', () => {
  const component = shallow(<Search />)
  const tree = shallowToJson(component)
  expect(tree).toMatchSnapshot()
})

Run npm t and you can see the difference. Instead of rendering out all the individual shows, we’re rendering stubs of ShowCard with the props going into each of them. This ends up being preferable since if ShowCard breaks, it won’t break this test. Run npm run update-test. You should see it updated your snapshot and now you’re good to keep going. Let’s test that if we search on the Search component, it displays the correct amount of shows.

// add two imports
import ShowCard from './ShowCard'
import preload from '../public/data.json'

// add new test at the bottom
test('Search should render correct amount of shows', () => {
  const component = shallow(<Search />)
  expect(preload.shows.length).toEqual(component.find(ShowCard).length)
})

Enzyme gives us lots of useful features. In this case, we can use it to do jQuery-like selections from our app. We can actually ask it, “How times does it use this React component”. Logically, based on how our app works, it should have a ShowCard for each item in the preload data, so that’s what we’ve checked here. Let’s take it a step further and see if it searches correctly.

// underneath the last test
test('Search should render correct amount of shows based on search', () => {
  const searchWord = 'house'
  const component = shallow(<Search />)
  component.find('input').simulate('change',{target:{value: searchWord}})
  const showCount = preload.shows.filter((show) => `${show.title.toUpperCase()} ${show.description.toUpperCase()}`.includes(searchWord.toUpperCase())).length
  expect(showCount).toEqual(component.find(ShowCard).length)
})

Here we’re making sure that the UI displays the correct amount of ShowCards for how many shows it should match. If I were to take this a bit further, I would extract that filter function to a module, test that, and then import that same function into the production environment and the test environment. Here we’re duplicating logic which isn’t the best idea.

We’re using Enzyme’s simulate function which simulate’s an event on the UI. Do note that as of present, this does not simulate event bubbling: you need to trigger the event on the same element that has the listener. We’re making sure that if we type into the search that it filters properly.

Enzyme has two other “depths” of rendering besides shallow: full DOM rendering and static page rendering. Full DOM uses jsdom to put the React app into a DOM-like environment if you need to interact with the DOM APIs. Unless you really need this, avoid it. It’s much slower than shallow rendering because jsdom takes a long time to bootstrap and run. You can also do static rendering which uses Cheerio to parse and interact with the resulting to HTML with a jQuery like environment. Again, I’d avoid this as it is much slower but if you need to do static analysis on the HTML, static rendering is the best way.

And now you get to hear my, Brian Holt’s, opinion on unit testing in React: I don’t. This is an unpopular opinion so please evaluate your own decision here. Because my markup changes so frequently as I seek to make the best user experience I can, tests are outdated as soon as they’re finished. Thus testing markup is counterproductive because they’re constantly failing and out-of-date. Rather, what I do is I extract important pieces of generally-useful pieces of logic and unit test the hell out of those. That way as my markup thrashes and changes, I can still re-use battle-tested pieces of logic to power the UI.

That being said, snapshot testing is so easy and so fast to update, it seems to be worth it to me. It’s such a new technology that it still remains to be proved out but as of present it’s something I recommend evaluating if it’s a good for you.

At this point you can go create tests for the other components but you’ve been taught how and you can go do so yourself. We’ll move on.

istanbul / nyc

A good-but-not-great metric of how well you’re testing your is code coverage. Basically it’s how much of your code gets covered by your tests. There exist many tools to do this but we’re going to use the most common in the JavaScript world: istanbul.

What istanbul is going to do? Istanbul instruments your code to see what code gets run and then lets you when your tests are covering and/or not covering other parts. Run npm test -- --coverage.

So let’s implement that as an npm script. Add:

"cover": "npm test -- --coverage"

Now if you run npm run cover you should see 100% coverage on Search and and 66% ShowCard. That means all the exported code is getting covered in a test for Search and only 2/3 of it is for ShowCard. Yay! But where are the rest of our files? Well, we’re not testing them at all yet so istanbul doesn’t know about them. Once you start testing those files they’ll show up.

Now go to the directory of your project and open in your browser coverage/lcov/index.html. This will let explore your project and see what’s being covered in our project. If you look at ShowCard, you’ll see that we’re not covering the render method which makes sense since shallow rendering stubs ShowCard and doesn’t let it render. What this means to you, at the very least, is that outside of the render method there’s no runtime error but inside of it may be. We should add a test to test render but that’s for another time!

A Note on Hot Module Reload

So webpack has a nifty ability to do what’s called hot module reload (HMR.) If you’ve ever used LiveReload’s CSS injection, this will sound familiar. HMR will take your code, compile it on the fly, and then inject it into your live-running code. Pretty cool tech.

If you’re working a dropdown that requires three different clicks to get there, it’s pretty neat to be able to change the code and watch the UI change without having to reload and get the UI back into a state where you can see the effects of your change.

But we’re not going to do it today. For one, HMR does not work with our stateless functional components at all. It also just requires a lot of setup that can be finicky at times. The author himself says the tech is a (great) hack.

So suffice to say, I want you to be aware of its existence and continuing evolution but I feel like our time is better off investigating other parts of the React ecosystem.

These problems are soon going to be resolved with react-hot-loader v3. However, it’s still in beta and not totally working and it wouldn’t be a great idea to talk about here. Feel free to checkout the newest version and if it’s landed then try it out!

Data in React

So now we want to add a third page: a page where we can watch the trailer. This is going to be an application of what we know already.

Create a new file in js/ called Details.js. In Details put:

import React from 'react'

const Details = React.createClass({
  render () {
    return (
      <div className='details'>
        <h1>lolhi</h1>
      </div>
    )
  }
})

export default Details

In ClientApp.js, put your new route:

// require your new route
import Details from './Details'

// add as last route in the nested routes
<Match pattern='/details/:id' component={Details} />

Here we’ve added a URL parameter using the colon. Now as a prop to Details you’ll get whatever :id was. So now try to manually change the anchor on your url to be http://localhost:8080/#/details/1. You should see your new component here.

Let’s show you a neat debugging tip I totally stole from Ryan Florence. replace that h1 with this:

// instead of the h1 in render
<pre><code>
  {JSON.stringify(this.props, null, 4)}
</code></pre>

// TODO
// at the bottom to shut up lint
Details.propTypes = {
  params: React.PropTypes.object
}

// ENDTODO

This is a useful way to dump your params to the page to see what react-router is giving you. This is awesome for state too; it shows you in real time what your state looks like. We’ll dig into React Tools here in a sec for even better debugging but for now let’s keep trucking with our Details.js.

We’re going to show all the details of a show on this page and be able to play the trailer. There’s a big problem here that we don’t have that data on this page though; it’s available in the Search route. We could require in data.json here given that our data is available that way but that typically isn’t the case: we typically get this data from the server. If that’s the case, you don’t want to make two AJAX requests to get the same data. In other words, we need to share this state between components. The way you do this is by pushing up the state to the highest common ancestor component. In this case, that’d be the router in ClientApp. So let’s first refactor Search to still work while it pulls in that data from Search.

// in ClientApp.js
// another import
import preload from '../public/data.json'

// modify the existing route
<Match pattern='/search' component={(props) => <Search shows={preload.shows} {...props} />} />

Now make Search use it

// delete import preload from '../public/data.json'

// pull out PropTypes
const { shape, arrayOf, string } = React.PropTypes

// add propTypes
propTypes: {
  shows: arrayOf(shape({
    title: string,
    description: string
  }))
},

// change the map map call
{this.props.route.shows
// instead of {data.shows

Cool. Now it should still work but Search no longer controls the data but merely receives it as props. Now we can share this data with Details. Another thing to notice is that with components, you can pass them functions that return markup, essentially a render function inside of component. Indeed you can do this anywhere you can put a components. These are called stateless functional components. We’ll see more of these later.

Now we’re going to pass the correct show to the Details page. There’s a bunch of ways to do this:

  • We could pass all the shows and let Details select the correct show. This isn’t great because Details is given an additional concern it doesn’t need to have.
  • We could create a callback in ClientApp that it passes to Details that Details calls with the correct ID and ClientApp hands back the correct show. This is slightly better but it’s an odd API for getting data. Ideally we just hand down props and not a callback, especially since this isn’t async.
  • Or we could hook into react-router’s ability to pass props down through stateless functions like we did with Search and just pass down the correct show. This is the best approach.

Add the following to ClientApp:

// replace Details Match component
<Match pattern='/details/:id' component={(props) => {
  const show = preload.shows.filter((show) => props.params.id === show.imdbID)
  return <Details show={show[0]} {...props} />
}} />

This should put the correct show as one of the props that ClientApp passes down to Details. If you refresh the page, you should see it now.

As an aside, I’ve found the best way to organize React method component is the following

  1. propTypes
  2. getInitialState / constructor
  3. Other lifecycle methods like componentDidUpdate (we’ll talk about those in a sec)
  4. Your methods you create (like assignShow)
  5. render

Makes it easier to find things when you look for them.

So let’s actually display some cool stuff:

import React from 'react'
const { shape, string } = React.PropTypes

const Details = React.createClass({
  propTypes: {
    show: shape({
      title: string,
      year: string,
      poster: string,
      trailer: string
    })
  },
  render () {
    const { title, description, year, poster, trailer } = this.props.show
    return (
      <div className='details'>
        <header>
          <h1>svideo</h1>
        </header>
        <section>
          <h1>{title}</h1>
          <h2>({year})</h2>
          <img src={`/public/img/posters/${poster}`} />
          <p>{description}</p>
        </section>
        <div>
          <iframe src={`https://www.youtube-nocookie.com/embed/${trailer}?rel=0&amp;controls=0&amp;showinfo=0`} frameBorder='0' allowFullScreen />
        </div>
      </div>
    )
  }
})

export default Details

Now you should have some nice looking UI.

Well, now we have a header in two places. That’s a strong indicator that you should make it’s its own component. Let’s abstract that in a component and use that in both places. Create a new file called Header.js and put this in there:

import React from 'react'
import { Link } from 'react-router'

const Header = React.createClass({
  render () {
    return (
      <header>
        <h1>
          <Link to='/'>
            svideo
          </Link>
        </h1>
      </header>
    )
  }
})

export default Header

We’re even going to throw in a link back to the home page for fun. Now open Details.js and put:

// add to the top
import Header from './Header'

// replace <header>...</header>
<Header />

Let’s put a back button on the Header so you can get back to Search after you reach it.

// after the h1 inside .header
<h2>
  <Link to='/search'>
    Back
  </Link>
</h2>

So let’s integrate this to Search. But it’s not so simple since on Search we want the header to have a search input and on Details we want a back button. So let’s see how to do that. In Header.js put:

import React from 'react'
import { Link } from 'react-router'
const { func, bool, string } = React.PropTypes

const Header = React.createClass({
  propTypes: {
    handleSearchTermChange: func,
    showSearch: bool,
    searchTerm: string
  },
  render () {
    let utilSpace
    if (this.props.showSearch) {
      utilSpace = <input type='text' placeholder='Search' value={this.props.searchTerm} onChange={this.props.handleSearchTermChange} />
    } else {
      utilSpace = (
        <h2 className='header-back'>
          <Link to='/search'>
            Back
          </Link>
        </h2>
      )
    }
    return (
      <header>
        <h1>
          <Link to='/'>
            svideo
          </Link>
        </h1>
        {utilSpace}
      </header>
    )
  }
})

export default Header

In Search.js:

// add to requires
const Header = require('./Header')

// replace <header></header>
<Header handleSearchTermChange={this.handleSearchTermChange} showSearch searchTerm={this.state.searchTerm} />

This is how you have a child component modify a parent’s state: you pass down the callback and let it call the parent to let the parent modify the state. This also demonstrates how to conditionally show one component and not another.

Lastly let’s make our show cards clickable.

import React from 'react'
import { Link } from 'react-router'
const { string } = React.PropTypes

const ShowCard = React.createClass({
  propTypes: {
    poster: string.isRequired,
    title: string.isRequired,
    year: string.isRequired,
    description: string.isRequired,
    imdbID: string.isRequired
  },
  render () {
    return (
      <Link to={`/details/${this.props.imdbID}`}>
        <div className='show-card'>
          <img src={`/public/img/posters/${this.props.poster}`} />
          <div>
            <h3>{this.props.title}</h3>
            <h4>({this.props.year})</h4>
            <p>{this.props.description}</p>
          </div>
        </div>
      </Link>
    )
  }
})

export default ShowCard

React Lifecycle Methods and AJAX with React

Due to the structuring of our app, we haven’t had to use React lifecycle methods despite the fact they’re fairly common to use and thus important to know. One of the most compelling reasons to use lifecycle methods is to do AJAX. Once a component gets mounted to the page then we want to be able request data from the server. First let’s discuss the lifecycle of a React component.

  1. constructor/getInitialState - This is where set up your components initial state. The former is for ES6 classes (that you’ll see how to do at the end) and the latter is for the React.createClass method (that we’ve been using.)
  2. componentWillMount - This method runs right before the component gets mounted. This one is not too common to use, but you will want to use it any time you want code to run both in node and in the browser.
  3. componentDidMount - This method runs right after your component gets put into the DOM. This method will not get run in node but will in the browser. This makes it so your component can render first then you can go get the data you need. In your component you can throw up a loader if you need to. Also if you need to interact with the DOM (like if you were wrapping D3 or a jQuery plugin) this would be the place to do it.
  4. componentWillUnmount - This method runs right before the component is taken off the DOM. Most common thing to do here is get rid of external event listeners or other things you need to clean up.

Cool! So let’s make our Details page check the IMDB rating! Open Details.js.

// import in axios
import axios from 'axios'

// add propType inside show
imdbID: string

// add getInitialState and componentDidMount to Details
getInitialState () {
  return {
    omdbData: {}
  }
},
componentDidMount () {
  axios.get(`http://www.omdbapi.com/?i=${this.props.show.imdbID}`)
    .then((response) => {
      console.log('response', response)
      this.setState({omdbData: response.data})
    })
    .catch((error) => {
      console.error('axios error', error)
    })
},

// add to render before return
let rating
if (this.state.omdbData.imdbRating) {
  rating = <h3>{this.state.omdbData.imdbRating}</h3>
} else {
  rating = <img src='/public/img/loading.png' alt='loading indicator' />
}

// add between year and poster
{rating}

We’re requiring in axios which is a great little promise-based AJAX client and using that to make requests to the Open Movie Database to find the IMDB ratings. If you go to your pages now you’ll notice that the rating is showing up a little after the page renders. That’s because it’s being grabbed from the magical Internet tubes! As you can see, we did this componentDidMount so that the user could see UI before waiting on an AJAX request. Note that it won’t get server-side rendered either because the server doesn’t call componentDidMount.

That’s it! That’s all you need to need know about AJAX with React as well as the lifecycle methods!

React Tools

So far we’ve been using pretty old school debugging technology: console.logs and just dumping stuff out to the DOM. There is an easier way! React Dev Tools! Grab it here for Chrome and Firefox. In theory you can get the Chrome version working on Microsoft Edge, but good luck. If you’re not using Chrome or Firefox, you’re out of luck for now. They’re talking about doing a standalone app but we’ll see when that finally surfaces. I’ll be talking about the Firefox version because that’s the one I know the best but this should apply to Chrome just as well.

Dev Tools allow you to explore the virtual DOM of React as if it was just a normal DOM tree. You can see what props and states are in each component and even modify the state of components. The virtual DOM explorer is by-far the most useful part of it.

Find the Dev Tools in Firefox by opening the dev tools and the last tab (along side Console, Sources, Network, etc.) should be React on your page. If you don’t see it try restarting your browser. If you still don’t see it, the tab won’t show up if the extension can’t detect React on the page. You may have a dated version of the dev tools. After that I’m not sure; it can be fickle sometimes.

Feel free to poke around a bit here to familiarize yourself with what the React Dev Tools can do. Here are a couple of tricks for you:

  • If you right-click -> Inspect Element on something and then click the React tab, it will take you straight to that element in the virtual DOM.
  • Select something in the virtual DOM in the React tab. Now go to the Console tab and type $r. It should be a reference to the element you have selected in the virtual DOM and you can manipulate it.
  • As a side note, you can do the above trick with the normal DOM explorer with $0, $1, $2, $3, and $4 instead where 0 is the last one you selected, 1 is the penultimate, etc. This is true in both Chrome and Firefox
  • iframes and Chrome/Firefox extensions don’t work with React Dev Tools as of writing.
  • react-router v4 has a lot of nesting.

redux

The next thing we want to do with our app is make the front page’s search work so that when you type in a search query and hit enter it will automatically have searched for that on the Search page. Right now you have all the necessary tools to do that via state. You could just push the query term up to the ClientApp level and then pass that down to the Search and you’d be done. And that’s the way you should do it given how small our app is.

But when these demo apps all the fun is in over engineering it and that’s precisely what we’re going to do: we’re going to add redux. redux is a fantastic tool and a cool blending of the ideas of Facebook’s Flux and the Elm architecture.

As a side-note, there are some super rad new tools out there like [Mobx][mobx] that you can check out, but we’re sticking to Redux. Mobx is incredible but with more power comes more complexity. If you learn Redux then learn Mobx (and reactive programming) you’ll really appreciate and/or fear the power that comes from Mobx.

So what is Redux? Redux is a predictable state container for JavaScript apps. The best part about it while the concept is at first hard, I’d argue it’s also very simple and elegant. Redux is great because it will run both client and server side, it’s easy to test, and easy to debug. While Redux does not not follow the Flux pattern, you can easily see the similarities and once you’ve done one the other isn’t hard to adapt to.

With Redux you a single store which stores your entire app state in a single tree. This is not like Flux where you’ll have many stores for many different parts of your app; all data lives in a single store. You cannot directly modify the tree of data stored in this tree by typical assignment (ie tree.prop = 'foo' doesn’t work.) Rather, every time you want to modify the tree, you emit an action. Your action then kicks off what’s called a reducer. A reducer is a special function that take a tree and parameter(s) and returns a new tree after applying whatever transformations it deems fit. The way it gets away with just one store is when you need more data you just add more branches to your data tree. Like React? You only have one tree of components and when you need more you just add more nodes (branches) to your components.

So let’s do the most basic addition of Redux to our app and convert the Search to use Redux. Again, this is using a sledgehammer to solve a tiny nail problem: huge overkill.

Create a reducers.js, put this in there:

const DEFAULT_STATE = {
  searchTerm: ''
}

const rootReducer = (state = DEFAULT_STATE, action) => {
  switch (action.type) {
    default:
      return state
  }
}

export default rootReducer

Create a store.js and put this:

import { createStore } from 'redux'
import rootReducer from './reducers'

const store = createStore(rootReducer)

export default store

This is about as bare bones as Redux gets: we boot strapped a Redux store with a single top-level reducer and exported that. One thing you’re going to find with Redux is there’s a long path to follow to follow how your state changes. A very predicatble and consistent path, but it’s still way longer than it used to be when we were just dealing with React state. This will often not be worth it. Evaluate this yourself on a per-project basis.

So like we said, each store starts with one reducer: the root reducer. This root reducer in turn will dispatch to other reducers. A few keys to notice here:

  1. You must return the finished state each time.
  2. You must handle action types you’ve never seen before (which why we have the default clause.)
  3. You take in state, you copy it, and you return a new state. That’s what any reducer does. If you return the same state, Redux thinks nothing happened and won’t inform React of any changes.
  4. You must have a default state.
  5. Redux by itself has no way of dealing with async actions. You need to pull in another library like redux-thunk. We’ll use that later.

Okay make a new file called actions.js and put in there:

export const SET_SEARCH_TERM = 'SET_SEARCH_TERM'

Create a file called actionCreators.js:

import { SET_SEARCH_TERM } from './actions'

export function setSearchTerm (searchTerm) {
  return { type: SET_SEARCH_TERM, searchTerm }
}

Now back to reducers.js:

// import at top
import { SET_SEARCH_TERM } from './actions'

// new reducer above rootReducer
const setSearchTerm = (state, action) => {
  const newState = {}
  Object.assign(newState, state, {searchTerm: action.searchTerm})
  return newState
}

// add new case before default inside rootReducer
case SET_SEARCH_TERM:
  return setSearchTerm(state, action)

More files! This should be it for our simple project. Actions is just going to a bunch of exporting of constants. Why do we do this? The way Redux’s root reducer decides to dispatch it to one of various reducers is by the action type. Thus it needs to match in both the action creator and the reducer. Rather than having magic strings, we have one central source of truth both file read from. Makes refactoring easy too.

The actionCreator is what the UI is actually going to interact with to make changes to the Redux store. In other words, your UI never directly interacts with the store nor the reducers. It only interacts with action creators which then are handled in the reducers which then change the store which then inform the UI of the changes. One way data flow!

If you haven’t seen the syntax const x = { searchTerm } it just means const x = { searchTerm: searchTerm }. It’s just a shortcut.

The rootReducer uses the same SET_SEARCH_TERM constant to hinge in the rootReducer. Also note we return a new object every time when we make a new object. This lets Redux know to inform any subscribers (in this case your React app) that changes happened.

Okay, so let’s go make landing interact with the store. But first we need to connect Redux to React via the react-redux package. Go to ClientApp.js.

// import react-redux and your new store
import { Provider } from 'react-redux'
import store from './store'

// wrap everything in router in provider
render () {
  return (
    <HashRouter>
      <Provider store={store}>
        []
      </Provider>
    </HashRouter>
  )
}

Provider connects React to Redux for you. Now you can magically use a connect function (also provided from react-redux) that allows you to pull in the pieces of state you need in each component. Let’s got make Landing.js read and write to Redux.

// imports at the top
import { connect } from 'react-redux'
const { string } = React.PropTypes

// add propType
propTypes: {
  searchTerm: string
},

// replace input
<input value={this.props.searchTerm} type='text' placeholder='Search' />

// at the bottom
const mapStateToProps = (state) => {
  return {
    searchTerm: state.searchTerm
  }
}

export default connect(mapStateToProps)(Landing)

Connect is a function that allows your component to tap into the Redux store’s state. The mapStateToProps allows you to select which pieces of state are passed into your component which helps keep thing clean. At the bottom we export a connected version of the component. Now if you reload the page the input doesn’t work for the same reason it didn’t with React previously: we are never sending the typed text to Redux to update its state. Let’s do that now.

// at top
import { connect } from 'react-redux'
import { setSearchTerm } from './actionCreators'

// inside React.createClass
propTypes: {
  searchTerm: string,
  dispatch: func
},
handleSearchTermChange (event) {
  this.props.dispatch(setSearchTerm(event.target.value))
},

// change input
<input onChange={this.handleSearchTermChange} value={this.props.searchTerm} type='text' placeholder='Search' />

// at the bottom
const mapStateToProps = (state) => {
  return {
    searchTerm: state.searchTerm
  }
}

export default connect(mapStateToProps)(Landing)

We’re importing the actionCreator we created to be able to dispatch the correct action. We’re then tying the input to a change handler and the prop that’s going to be passed in. At the bottom we’re connecting this component to Redux via connect. mapStateToProps takes in the whole state tree via the state param and returns which props you want passed into the component. Connect makes that magic happen and also passes in a dispatch function which allows to dispatch actions to Redux via our actionCreators. Inside the change handler we do just that: call this.props.dispatch and call the actionCreator here. While this seems like a weird contract to deal with, it’s worth it. The contract is that you can always pass dispatch the result of a actionCreator. For normal, synchronous actions like this it’s a little convuluted but once we start dealing with async actions this contract helps a lot to simplify your UI code and contain the chaos to your actionCreators. Let’s make it actually transition to Search.js once you hit enter.

// add contextTypes
contextTypes: {
  router: object
},

// add method to Landing
goToSearch (event) {
  event.preventDefault()
  this.context.router.transitionTo('/search')
},

// surround input with form
<form onSubmit={this.goToSearch}>
  <input onChange={this.handleSearchTermChange} value={this.props.searchTerm} type='text' placeholder='Search' />
</form>

So we’re introducing a new concept here from React: context. This is a dangerous tool and I will tell you I personally have never put anything on context. I’ve only consumed things from context that libraries like react-router and react-redux (which both do use context) put on there. Use at your own peril.

Context is basically global state: anywhere inside a React app can read and write to state. If this sounds nightmarish to you then you have good sense: it defeats a lot of the benefits to React. However, with something like react-router it’s very useful because the whole app does care about routing, as it does about Redux.

Notice the contextTypes are like propTypes. However, contextTypes are even more important to React than propTypes: if you don’t have them the object you’re looking for won’t be there. In other words, you must identify in contextTypes the properties the component cares about or they will not be available on context.

Okay, so we’re using a form to take care of when hits enter: this is good for accessibility and a good way to take care of submitting. Once a user hits enter, it calls goToSearch where we imperatively call the router to take us to search. This will preserve our Redux state; however Search.js is not yet reading from Redux. Let’s go fix that.

// import at top
import { connect } from 'react-redux'

// add propType not inside shows
searchTerm: string

// change header
<Header showSearch />

// change state to props inside of filter
.filter((show) => `${show.title} ${show.description}`.toUpperCase().indexOf(this.props.searchTerm.toUpperCase()) >= 0)

// add at bottom, replace export
const mapStateToProps = (state) => {
  return {
    searchTerm: state.searchTerm
  }
}

export default connect(mapStateToProps)(Search)

Notice we got to delete a lot of code. Always feels good! We’re externalizing our state management so that’ll happen more as well. Also notice that Search no longer cares about modifying searchTerm since it itself doesn’t need to. This is cool; having concerns live where they happen is a really positive thing. Otherwise not much new here. This will work now if you go to Landing and submit a search term from there. However we’ve broke the header. Let’s go fix that.

// import at top
import { connect } from 'react-redux'
import { setSearchTerm } from './actionCreators'

// delete handleSearchTerm propType
// add to propTypes
dispatch: func

// add method to Header
handleSearchTermChange (event) {
  this.props.dispatch(setSearchTerm(event.target.value))
},

// change input to not call this.props.handleSearchTermChange but this.handleSearchTermChange (not on the state object)
utilSpace = <input type='text' placeholder='Search' value={this.props.searchTerm} onChange={this.handleSearchTermChange} />

// at the bottom
const mapStateToProps = (state) => {
  return {
    searchTerm: state.searchTerm
  }
}

export default connect(mapStateToProps)(Header)

Since Header does care about modifying searchTerm we bring in that logic here. Otherwise not much changes!

redux Devtools

One of the most compelling reason to use redux is its amazing debugging experience. redux has the fantastic ability to do time-traveling debugging, meaning you can step forwards and backwards through actions you’ve dispatched. It’s really powerful for debugging.

There are several ways to get it working but I’m going to show you the bare minimum to get up and running. Unlike React, there is some code you have to put in to get it working. Luckily, it’s like two or three lines.

In Store.js put:

import { createStore, compose } from 'redux'
import rootReducer from './reducers'

const store = createStore(rootReducer, compose(
  typeof window === 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : (f) => f
))

export default store

That’s it for code! It just adds a middleware to redux that hooks into the dev tools. It’s also doing a window check to make sure if you’re unit testing or running your components in node that the window reference doesn’t blow up.

Now go grab the Chrome extension or Firefox extension. The Safari one is forthcoming. Good news is that you can actually just build the debugger into the page so it works everywhere. Bad news is I’m going to show you how since I’ve never done it. In any case, feel free to explore it on your time.

Okay, last bit: this doesn’t work with the file:/// protocol. But luckily we’re using webpack-dev-server so it doesn’t matter.

Now you should see three green circles with smaller orange circles circling the green ones on your Chrome or Firefox tool bar. Click on that and that should show you the redux tools. This allows you to play with the redux tools. I’ll let you toy with them but suffice to say they’re pretty impressive.

Async Redux

Async Redux

Redux by default has no mechanism for handling asynchronous actions. This means you either need handle everything async in your React (gross) or we have to augment Redux to handle async code. The former is really a non-starter: the point of Redux is centralize state manipulation and not having the ability to do async is just silly. We’re building interfaces and interfaces are inherently asynchronous.

Okay, so we’ve decided to augment Redux. How do we do that? Well, luckily, Redux has the ability to have middlewares, just like your server can. What we can do is add a middleware that can handle more than just action objects. There are a myriad of popular ones but we’re going with the most popular, the simplest, and the easiest: redux-thunk. I’ll venture to say that if you build any Redux app, rarely are you not going to include redux-thunk, even if you include one of the other async Redux middlewares. It’s frequently useful, even beyond it’s async applications.

So let’s unpack the word thunk: it’s a weird computer science term that seems more difficult than it actually is. Imagine you need to write a line of code that calculates the conversion from USD to EUR. You could write it:

const dollars = 10
const conversionRate = 1.1
const euros = dollars * conversionRate

This code is a bit weak because we’ve statically defined the conversionRate. It would be better if we didn’t have to define this value statically but instead could be determined whenever you accessed conversionRate (since currency exchange rates flucuate constantly.) What if we did:

const dollars = 10
const conversionRate = function () { return 1.1 }
const euros = dollars * conversionRate()

Now we’ve wrapped conversionRate in a function. Even though the answer is unchanged, conversion is now a black box that we can swap out that 1.1 whenever. The value of the return of conversionRate isn’t set until that function is actually called. conversionRate is now a thunk. It’s a function wrapping a value.

The above is a silly example, but it with Redux this becomes a powerfuly feature. Instead of determining what action object you’re going to dispatch at write time, you can determine what you’re going dispatch conditionally or asynchronously. redux-thunk even let’s you dispatch multiple actions! This can be useful if you have one action that leads to multiple, cascading changes. Super useful. So let’s go change the Details page to use redux-thunk instead of local state. First, let’s go include the redux-thunk middleware. Go store.js:

import { createStore, compose, applyMiddleware } from 'redux' // add applyMiddleware
import thunk from 'redux-thunk' // import
import rootReducer from './reducers'

const store = createStore(rootReducer, compose(
  applyMiddleware(thunk), // middleware
  typeof window === 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : (f) => f
))

export default store

This is how you add more middlewares! Okay, so let’s go add the sync action to make it so we can store omdbData in our data store. This is a good distinction to make: you still will only modify your state via reducers, and reducers are only kicked off via dispatching action synchronously to your root reducer. Always. So what we’re doing is kicking off an async action which when it finishes will dispatch a sync action to the root reducer. We’re just adding another step. So let’s do our sync action. Go to actions.js:

export const ADD_OMDB_DATA = 'ADD_OMDB_DATA'

Now go to reducers.js:

// at top
import { SET_SEARCH_TERM, ADD_OMDB_DATA } from './actions'

const DEFAULT_STATE = {
  searchTerm: '',
  omdbData: {}
}

// add new reducer
const addOMDBData = (state, action) => {
  const newOMDBData = {}
  Object.assign(newOMDBData, state.omdbData, {[action.imdbID]: action.omdbData})
  const newState = {}
  Object.assign(newState, state, {omdbData: newOMDBData})
  return newState
}

// add new case
case ADD_OMDB_DATA:
  return addOMDBData(state, action)

Doing some deep merging, but really nothing new here. Go to actionCreators.js:

import { SET_SEARCH_TERM, ADD_OMDB_DATA } from './actions'
import axios from 'axios'

export function setSearchTerm (searchTerm) {
  return { type: SET_SEARCH_TERM, searchTerm }
}

export function addOMDBData (imdbID, omdbData) {
  return { type: ADD_OMDB_DATA, imdbID, omdbData }
}

export function getOMDBDetails (imdbID) {
  return function (dispatch, getState) {
    axios.get(`http://www.omdbapi.com/?i=${imdbID}`)
      .then((response) => {
        dispatch(addOMDBData(imdbID, response.data))
      })
      .catch((error) => {
        console.error('axios error', error)
      })
  }
}

First we add an action creator for our sync action, addOMDBData. This is personal preference but I always make action creators that dispatch object a separate function. I could have done this directly inside of getOMDBDetails (and many people do) but I like keeping it separate for code organization and reuseability.

So let’s unpack getOMDBDetails. First this is to notice that it’s a function that returns a function, a thunk. Redux will call this returned function (you call the outer one and pass that to dipatch) and pass into this returned function a dispatch function and a getState function. We `don’t need getState, but if your actionCreator needs to refer to the state of the Redux store, you’d call this function.

Inside of the returned function, we make our AJAX call and then dispatch an action via the addOMDBData action creator with the new data. That’s it! This is a pretty simple (and common) application of thunk, but you can get much more robust with it. Since you have a dispatch function, you’re free to dispatch multiple actions, or not dispatch any at all, or conditionally dispatch one/many/none. Okay, so now head to Details.js to integrate it.

// new imports
import { connect } from 'react-redux'
import { getOMDBDetails } from './actionCreators'

// import func
const { shape, string, func } = React.PropTypes

// more propTypes (outside of show)
omdbData: shape({
  imdbID: string
}),
dispatch: func

// replace componentDidMount
componentDidMount () {
  if (!this.props.omdbData.imdbRating) {
    this.props.dispatch(getOMDBDetails(this.props.show.imdbID))
  }
},

// change state to props in render
if (this.props.omdbData.imdbRating) {
      rating = <h3>{this.props.omdbData.imdbRating}</h3>

// replace export at bottom
const mapStateToProps = (state, ownProps) => {
  const omdbData = state.omdbData[ownProps.show.imdbID] ? state.omdbData[ownProps.show.imdbID] : {}
  return {
    omdbData
  }
}

export default connect(mapStateToProps)(Details)

Okay, so now we have an interesting side effect of moving from React to Redux: when we were in React whenever we navigated away from a Details page, we lost the data we requested from OMDB and we’d have to re-request it anew every time we navigated to the page. Now since we’ve centralized to Redux, this data will survive page transitions. This means we need to be smart and only request data when we actually don’t have it, hence the conditional in the componentDidMount method. If we already have data, no need to dispatch the action!

In the mapStateToProps, we’re including the ownProps parameter. This is the props being passed down from its parent component which we need to select the correct show to pass in as props. It also has the benefit of making connect subscribe to props change so that mapStateToProps will change as the props change. If we suddenly switched the imdbID being passed in, this would still work just fine.

That’s it! That’s async Redux, or at least the simplest form of it. Like I alluded to earlier, there are several other ways of accomplishing async Redux. The other popular options include redux-promise where you dispatch promises, redux-observable where you dispatch observables, and redux-sagas where dispatch generators.

Fixing Our Tests and Testing Redux

So we broke all of our tests. They all fail now. High five! This is a big reason why I’m hesitant to test UI code: I find my tests break all the time just because I’m rewriting markup or other code. Nonetheless, let’s refix our tests and add two for Redux. As opposed to testing React which I don’t do much of, I test the hell out of my Redux code. Redux code is very testable by design and you should cover all or nearly-all of your reducers with tests.

At the end of Search.js add:

export const Unwrapped = Search

We need an “unconnected” version of Search to test. We’re decoupling this from Redux so we can just test the React portion. It will still work without Redux as long as we pass in proper parameters. Go to Search.spec.js.

// import the new Unwrapped Search as just Search
import { Unwrapped as UnwrappedSearch} from './Search'

// in the first test, change the shallow call
const component = shallow(<UnwrappedSearch shows={preload.shows} searchTerm='' />)

// in the second test, change the shallow call
const component = shallow(<UnwrappedSearch shows={preload.shows} searchTerm='' />)

// go ahead and comment out the last test so we can test these first two first

Once we provide the proper params, these tests will be able to pass again. The snapshot is going to fail because we wrapped Header with a connect but go ahead and run npm run update-test to take care of that.

Since the last test tests the integration of Header and Search which were previously married together, we’re going to need to do two things: switch our render to be able to render Header inside of Search instead of just stubbing it out and we’re going to have to bring in Redux and integrate that.

// imports at top
import { Provider } from 'react-redux'
import store from './store'
import { setSearchTerm } from './actionCreators'
import { shallow, render } from 'enzyme' // add render import

// replace last test
test('Search should render correct amount of shows based on search', () => {
  const searchWord = 'house'
  store.dispatch(setSearchTerm(searchWord))
  const component = render(<Provider store={store}><Search shows={preload.shows} /></Provider>)
  const showCount = preload.shows.filter((show) => `${show.title.toUpperCase()} ${show.description.toUpperCase()}`.includes(searchWord.toUpperCase())).length
  expect(showCount).toEqual(component.find('.show-card').length)
})

We need to simulate events to Redux instead of to the DOM. Ultimately this isn’t a big deal since you should be testing that action creator individually anyway. We also need to use Provider to make Redux work for Header since that’s how Header and Search communicate now. Also, we can’t do the ShowCard component trick anymore with render since it’s not stubbing out ShowCard so we’re just checking for the CSS class instead.

There’s a layer deeper that you can go with Enzyme: static rendering with Cheerio. If you need to do serious manipulation, this is the tool you need to go with. Be forewarned this slows down startup a lot since it brings in jsdom and it is slow as 💩 to start up.

Cool! Let’s go test Redux now.

One of the primary reasons to use Redux is how testable it is. It was a big part of its design. Redux makes you create pure functions. These functions are then able to pulled out and thoroughly tested. And, lucky for us, Redux dev tools now lets you generate test automatically! Open Search and paste the word “orange” in there. We paste it so it’s one atomic operation. Open the Redux dev tools and select the last action. Click on the test tab. You’ll see an automatically generated test! Copy that and paste it into reducers.spec.js. You may have to mess with the paths to get it correct. And get rid of the semi-colons!

import reducers from './reducers'

test('SET_SEARCH_STATE', () => {
  let state
  state = reducers({searchTerm:''}, {type:'SET_SEARCH_TERM',searchTerm:'orange'})
  expect(state).toEqual({searchTerm:'orange'})
})

Free tests. All we have to do is recreate what we want to test, copy, paste, and commit! Pretty slick. In this particular case, it’s not terribly interesting. But you can’t beat how low effort it is to get a test out the door. And if you have to later throw this test away you won’t care because it was a minute to create start-to-finish. And if you get more complex Redux actions you can save a lot of time doing this. Let’s also grab the @@INIT action to make sure we bootstrap the way we think.

test('@@INIT', () => {
  let state
  state = reducers(undefined, {})
  expect(state).toEqual({searchTerm:''})
})

You can also test your actionCreators by making sure they craft their action objects correctly but I’ll leave that to you. For now this is enough!

Universal Rendering

Universal rendering, or the artist formerly known as isomorphic rendering. The idea here is that you server-side prerender your code so that when it gets down to the client, your browser can instantly show the markup while your app bootstraps in the background. It makes everything feel very instantaneous.

With just vanilla React, universal rendering is a cinch. Check out the whole node file from another one of my workshops. It does server-side rendering in just a few lines.

It’s not quite so simple now that we have routing involved. We don’t want to have to duplicate all of our routing info that we wrote for react-router. Rather, if possible, we just want to reuse the routes we already built for react-router. So let’s do that (with some refactoring.)

First thing is we need to split browser concerns away from our app. Right now ClientApp.js worries about the creating the base app and rendering it to the DOM. We need to do a few things to satisfy those requirements. First let’s split the app into browser and app concerns. Create a new file called App.js and put this in there:

import React from 'react'
import { Match } from 'react-router'
import { Provider } from 'react-redux'
import store from './store'
import Landing from './Landing'
import Search from './Search'
import Details from './Details'
import preload from '../public/data.json'

const App = () => {
  return (
    <Provider store={store}>
      <div className='app'>
        <Match exactly pattern='/' component={Landing} />
        <Match pattern='/search' component={(props) => <Search shows={preload.shows} {...props} />} />
        <Match pattern='/details/:id' component={(props) => {
          const show = preload.shows.filter((show) => props.params.id === show.imdbID)
          return <Details show={show[0]} {...props} />
        }} />
      </div>
    </Provider>
  )
}

export default App

Now all ClientApp.js should be is:

import React from 'react'
import { render } from 'react-dom'
import { BrowserRouter } from 'react-router'
import App from './App'

render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('app'))

Now all browser concerns lie in ClientApp and the general app has been split out and is ready to be server renderered. We’ll use a special ServerRouter for server rendering so that’s why we put the BrowserRouter inside of ClientApp.

Also, since App itself carries no state, we put it inside of a stateless functional component. I typically default to this kind of component and only migrate to React.createClass when I need lifecycle methods or need to keep track of state. They’re great because they’re simpler.

Okay, copout here: doing CSS modules in server-side rendering is going to add a bunch of complexity that with how little we’re using CSS modules. It’s possible, you need to pull in isomorphic-style-loader instead of css-loader, but we’re skip it for now. Remove/comment-out the css imports inside of Landing.js and add them to the head in index.html. Change index.html to look like:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vidflix</title>
  <link rel="stylesheet" href="/public/normalize.css" />
  <link rel="stylesheet" href="/public/style.css" />
</head>
<body>
  <div id="app"><%= body %></div>
  <&NegativeMediumSpace;script src="/public/bundle.js"></script>
</body>
</html>

We also added a lodash template tag in it. We’ll use it as we server-side render.

Go to .babelrc and add env, for server. For now it’ll be the same as test (since we need Babel to make the modules to CommonJS here too) but we don’t want to tie those together.

{
  "presets": [
    "react",
    ["es2015", {modules: false, loose: true}]
  ],
  "env": {
    "server": {
      "plugins": ["transform-es2015-modules-commonjs"]
    },
    "test": {
      "plugins": ["transform-es2015-modules-commonjs"]
    }
  }
}

Okay, let’s create a server now! Create a server.js outside the js folder and put it just in the root directory of your project. Put:

require('babel-register')

const express = require('express')
const React = require('react')
const ReactDOMServer = require('react-dom/server')
const ReactRouter = require('react-router')
const ServerRouter = ReactRouter.ServerRouter
const _ = require('lodash')
const fs = require('fs')
const port = 5050
const baseTemplate = fs.readFileSync('./index.html')
const template = _.template(baseTemplate)
const App = require('./js/App').default

const server = express()

server.use('/public', express.static('./public'))

server.use((req, res) => {
  const context = ReactRouter.createServerRenderContext()
  let body = ReactDOMServer.renderToString(
    React.createElement(ServerRouter, {location: req.url, context: context},
      React.createElement(App)
    )
  )

  res.write(template({body: body}))
  res.end()
})

console.log('listening on ' + port)
server.listen(port)

We’re switching back to CommonJS here to work with Node; Node doesn’t natively understand ES6 modules so we need to use CommonJS. We require in a bunch of stuff. We’re using Lodash templates but that’s a detail; I just did it since it’s an easy way to template. There’s ten billion other ways to do it. We do some static serving for our CSS. And then we do the magic of server side rendering.

Notably here we are not handling the 404 or redirect case. react-router is able to handle these without a ton of effort, both server and client-side, but we’ll get to that later. With the createElement stuff is just like we were at the beginning of the workshop; it’s just here we’re doing out of necessity since Node can’t read JSX either.

babel-register at the top lets us require modules that need transpilation. This isn’t ideal; in production you’ll probably want to pre-transpile them so you don’t continually pay that cost.

Okay. Let’s run the app. Run in your CLI npm run build then run NODE_ENV=server node server.js. Make sure you re-run build because the webpack-dev-server doesn’t necessarily re-write out the bundle.js. Okay, so now try going to localhost:5050. While you won’t necessarily notice it loading quicker since you were developing locally, check out view source. You should see it ships with a bunch of markup which means your page will load much quicker on a slower connection since markup will start rendering before the JS is done downloading.

Congrats! You’ve done server-side rendering!

Webpack Code-Splitting and Async Routing

So far all of our routing with react-router has synchronous which makes sense. When we detect that a user has requested a route, we already have that route in our bundle.js and we render and serve that to them. The logic follows.

However, as our app grows and grows, our bundle.js is going to get bigger and bigger in file size. Wouldn’t it be better if you were on Search that it served you just the JavaScript you need for that page and none of the JS for Landing or Details? For example, Search doesn’t need the axios client we brought in: that client can safely just be loaded on the Details page.

Enter webpack’s code splitting ability. It’s smart enough to know which files are required by which other files and thus if you choose to use webpack’s async loading API (require) then webpack will automatically start chunking your JS for you. What’s more is we don’t have to write the glue code that will download the chunks as we need them: webpack just does this for us. All we have to do is identify the modules that can be async by treating them as if they were. Really cool.

So we’re going to treat all of our routes as async and luckily react-router is already instrumented for this for both server and client-side. So let’s go make it happen! We’re going to be using to do this. There are many ways to do this; I’ve just found this easiest to teach you. People right now like react-modules despite it having some issues with server-side rendering.

So first we need give a minor tweak to webpack.config.js.

// inside of the output config object (not the devServer object)
publicPath: '/public/'

First we need to tell webpack where to find all of its bundles instead when it calls back to the server to grab them.

Let’s go create a component that will handle our asynchronous routes to contain all that craziness. Create a file called AsyncRoute and go there.

import React from 'react'
const { object } = React.PropTypes

const AsyncRoute = React.createClass({
  propTypes: {
    props: object,
    loadingPromise: object
  },
  getInitialState () {
    return {
      loaded: false
    }
  },
  componentDidMount () {
    this.props.loadingPromise.then((module) => {
      this.component = module.default
      this.setState({loaded: true})
    })
  },
  render () {
    if (this.state.loaded) {
      return <this.component {...this.props.props} />
    } else {
      return <h1>loading...</h1>
    }
  }
})

export default AsyncRoute

AsyncRoute is going to passed a promise which will resolve to a module. Once that promise has completed, that means the module is loaded and available. Then we can render it. Notice that we stick the module on this and not into state. Modules are large and it would slow down our component to have so much state. Furthermore we don’t expect it to change. Before that we’ll render a loading state. That’s all we’re going to do with AsyncRoute. Go to App.js

// at top
// delete Landing import
import AsyncRoute from './AsyncRoute'
if (global) {
  global.System = { import () {} }
}

// replace Landing Match
<Match
  exactly
  pattern='/'
  loadingPromise={(props) => <AsyncRoute props={props} component={System.import('./Landing')} />}
/>

So now we’re using our AsyncRoute function to make Landing Async. First we import our route and then we have to shim System.import out. Node doesn’t have System.import (it’s tied to the new ES6 module system which Node doesn’t have yet.) Then we pull in our async route and use it inside of Match. This is amazing since Webpack knows to perform a code split here and we get all the rest of that for free.

Let’s talk about what sucks about this. Now, server-side rendered or not, we get a loading screen first thing. No matter what. Ideally we get this loading screen sooner but nonetheless that happens. There are ways around this but it involves either making some compromises by not server-side rendering properly and getting a checksum violation or by greatly increasing the complexity of this by introducing the concept of module hydration where on the server you make sure to send down the bundle and the correct chunk at the same time and detect that on the client. For now I’m happy just introducing code-splitting to our app for now.

Also, in order for System.import (or require.ensure, which is the CommonJS version) to be able to code split, the parameter passed to it must be a string of the path. It cannot be a variable. Webpack is doing static analsysis of your code and cannot follow variables.

Open up your browser to /search (without hitting / first) and watch the network tab. Make sure your npm run watch and your npm run start are both running. You should see bundle.js being downloaded but you should also see 0.bundle.js being downloaded too. This is the chunks that Webpack is sending down piecemeal, meaning your route and associated modules are not included in the initial payload. This becomes a bigger and bigger deal as your app expands. Let’s finish the rest of our async routes.

// delete Search and Details import

// replace Details and Search matches
<Match
  pattern='/search'
  component={(props) => {
    return <AsyncRoute props={Object.assign({shows: preload.shows}, props)} loadingPromise={System.import('./Search')} />
  }}
/>
<Match
  pattern='/details/:id'
  component={(props) => {
    const show = preload.shows.filter((show) => props.params.id === show.imdbID)
    return <AsyncRoute props={Object.assign({show: show[0]}, props)} loadingPromise={System.import('./Details')} />
  }}
/>

Nothing too crazy here either. Just extendingo out the same ideas. Now try navigating around your app and watch the network tab. You should different bundles being pulled in. If you look at your terminal output, you’ll see we actually haven’t optimized too much: our main bundle is nearly a megabyte and the smaller bundles are between three and fifty kilobytes. Like I said, this is wonderful for big apps where you can section off where dependencies. For example the fifty kilobyte bundle is the only one that has axios. The rest of the app doesn’t need it. But for our tiny React routes, this isn’t super useful. And the ability to codesplit isn’t free either: Webpack includes some glue code to make this work. So evaluate this tool carefully!

Preact

So this is a React work, why the 💩 are we talking about [Preact][preact]? Let me tell you why! Preact is amazing! Preact is an almost drop in replacement for React that is much smaller in file size while maintaing nearly all the features and actually being faster (or so my limited, flawed benchmarking leads me to believe.) One thing is for sure though, it’s much smaller!

It sounds just better, right? Well, it’s certainly something you and your company should discuss. Preact is just 3KB gzipped; that’s really small! React for comparison’s sake is around 80KB, give or take 10KB. That’s a huge difference! The way Preact is able to achieve a lot of the size difference is by cutting out some of the legacy bits of React, letting browser do more, and focusing on a smaller API.

Speaking of a smaller API, we can’t switch to Preact wholesale as-is right now; we’re using the React and ReactDOM package everywhere. In addition, we’re using propTypes (Preact doesn’t have those) and the createClass syntax (Preact only supports ES6 classes and stateless functional components.)

So instead we’re going to drop in the preact-compat library which backfills those APIs at the cost of adding 5KB to your payload; still a win. preact-compat gets you started on your migration; eventually you want to drop it and just be on Preact.

So we’re going to super quick migrate to Preact for the client side. In webpack.config.js, add:

// inside resolve
alias: {
  react: 'preact-compat',
  'react-dom': 'preact-compat'
},

// inside 'babel-loader' loader
include: [
  path.resolve('js'),
  path.resolve('node_modules/preact-compat/src')
]

The include parts is just telling babel-loader to only run on files that are in the js directory (our code) or in the preact-compat directory. We should have done this sooner since this will speed up your build by not running on every file in node_modules.

The alias bit is telling webpack that everytime in our app we ask for react or react-dom, to actually give it preact-compat (which itself encompasses Preact.) Now build your app for production and compare! In my local env, I’m seeing a difference of 96.2KB vs 228KB for production builds. Not bad!!

Our server more-or-less works as is. It’s not ideal; honestly you’d want Preact doing both server and client work, but this is good for now. If you want to make it work, you’ll need to make Babel alias React to Preact instead of Webpack since that runs both client and server side whereas Webpack doesn’t.