I Learned How to be Productive in React in a Week and You Can, Too

Avatar of Sarah Drasner
Sarah Drasner on (Updated on )

📣 Freelancers, Developers, and Part-Time Agency Owners: Kickstart Your Own Digital Agency with UACADEMY Launch by UGURUS 📣

This article is not intended for seasoned React pros, but rather, those of us who make websites for a living and are curious how React can help us reason about updating user interfaces. I’ve been intrigued by React for some time, and now that it has gained some standing in the community as well as good reviews, the time to learn it seemed justified. There are so many new technologies constantly emerging in front end development that it’s sometimes hard to know if effort into learning something new will pay off. I’ll spend this article going over what I think some of the most valuable practical takeaways are so that you can get started.

Fair warning

I’ve only spent about a week working with this material. That’s on purpose. I’m writing this while I’m fresh with the technology and can write about it from that perspective. In this state I’m much better at remembering the tumbling blocks and findings along the way.

I used Wes Bos’ React for Beginners course, as well as React.js Introduction For People Who Know Just Enough jQuery To Get By. I could not recommend these resources more highly.

In two days, I made this:

See the Pen Baby’s First React Attempt by Sarah Drasner (@sdras) on CodePen.

It is imperfect, but it goes much farther than I would have gotten on my own in that amount of time.

If you’re the kind of person who wants to dive right in and learn it all, including the build and requisite tooling, that’s awesome! Here’s where to start. I would also suggest this pretty great Frontend Masters course: Modern Web Apps.

Mythbusters: Practicality in React Edition

Before we get started, there are a couple of key myths I’d like to debunk that I think are blockers for a lot of people.

Myth #1: You have to use inline styles to use React.

Nope! Not at all. You can use CSS just as you normally do. Having just spent a lot of time refactoring a giant CSS codebase, I would say that this is pretty important to establish. React, being fairly new, has not yet had to stand the test of design refreshes like other technologies have. If I had had to go back through thousands of lines of inline styles just to update things like padding and line-height, that would make me a sad developer indeed.

That said, there are times when inline styles do make sense. If you have a component that will change styles depending on its state (for instance: a data visualization) it would make absolute sense to work with inline styles so that you’re not maintaining an impractical number of static styles (in multiple places) to handle all possible states.

I’d think, though, that this would be on top of a base CSS that the application uses and be an exception rather than a rule. The web is a big place, though, so there are no absolutes.

Myth #2: You have to use JavaScript syntax for element attributes, which is not at all like HTML.

One of the things I really love about Wes Bos’ teaching style is that he guides the viewer towards the more familiar approach and implementation. I generally like to err on the side of simple, and less obfuscated code, though I understand that others like higher degrees of abstraction.

He suggests that we write our markup with JSX, which more closely resembles our friend, traditional HTML, so I found it to be much more clear. So, instead of this:

return React.createElement("p", {className: "foo"}, "Hello, world!");

We would write this:

return (<p className="foo">Hello, world!</p>);

Either works. But when we start to have more and more complexity in our markup, I found that the familiarity of HTML in the form of JSX served my understanding. Please keep in mind, though, that even with JSX, there are minor differences.

Myth #3: In order to try React, you have to understand all of the build tools.

It’s true that in order to use React, you need to use build tools, so this is usually what tutorials start with. I would recommend, though, that as a total beginner, you should muck around on CodePen. It’s a good way to iterate quickly and learn before investing a lot of time in a brand new technology.

Using React in Typical Applications

In typical applications using React 1.14+ we would start out by requiring React and ReactDOM:

var React = require('react');
var ReactDOM = require('react-dom');

And then call ReactDOM.render:

ReactDOM.render(routes, document.querySelector('#main'));

Using React in CodePen

In our case, we will simply be selecting React from the dropdown in the JS panel (click the cog icon at the top of the panel), and then using Babel as the compiler.

We don’t need to require React or React DOM, since we haven’t routed anything, we’re using the app component directly. Our code will be amended simply to:

React.render(<App/>, document.querySelector("#main"));
<div id="main"></div>

Also, in order to get started, you’re going to need the React Devtools extension for Chrome, or React Devtools Extension for Firefox which is great for debugging our virtual DOM.

If CodePen, you can use Debug View and it will find React properly:

Up and running

The basic building blocks that you need to know to make something is as follows:

// App
var App = React.createClass({
  render: function() {
    return (
      <div className="foo">Hello, world!</div>
    )
  }
});
 
ReactDOM.render(<App/>, document.querySelector("#main"));

See the Pen Hello World React by Sarah Drasner (@sdras) on CodePen.

Let’s break this down. On the last line we find the main div id, and on that we render the <App /> component, which will load all of our React application. You can use your React tab in Devtools to now see the DOM element we’ve created.

We’ve attached <App /> as the first component. The first thing to note here is that this tag is capitalized — while this isn’t required it’s a best practice with React components. The second is that it is self-closing. Tags in react must be closed, either by an additional closing tag (e.g. </div>), or a self closing tag (e.g. <hr> would become <hr />). This is just how JSX works and an error will be thrown otherwise.

Note the structure for creating the app component at the top. You will get very used to this syntax moving forward, as everything we will build today will work off of this key building block.

The last thing to note is that rather than using class, we’re using className on the element. This is a gotcha if you’re used to writing HTML markup for a webpage. Luckily, it’s easily solved. For more information on JSX and its syntax, these docs are really good resources.

// App
var App = React.createClass({
  render: function() {
    return (
      <Header />
    )
  }
});
 
// Header
var Header = React.createClass({
 render: function() {
   return (
     <div className="foo">Hello, world!</div>
   )
 }
});
 
ReactDOM.render(<App/>, document.querySelector("#main"));

See the Pen Hello World React by Sarah Drasner (@sdras) on CodePen.

In the next step, we’re extending app with a component. Header can be named whatever you would like it to be named, for clarity, we’ve named it the role it has in the document. You can see that if we also wanted to add a navigation element, that would be quite simple to add. Here’s the same page with just a standard bootstrap row of buttons for a <Nav /> component, and the more semantic h1 for our “Hello, World!” instead of a div:

// App
var App = React.createClass({
render: function() {
 return (
   <div>
     <Nav />
     <Header />
   </div>
  )
 }
});
 
// Nav
var Nav = React.createClass({
 render: function() {
   return (
    <ul className="nav nav-pills">
      <li role="presentation" className="active">Home</li>
      <li role="presentation">Profile</li>
      <li role="presentation">Messages</li>
    </ul>
  )
 }
});
 
// Header
var Header = React.createClass({
 render: function() {
   return (
     <h1 className="foo">Hello, world!</h1>
   )
 }
});
 
ReactDOM.render(<App/>, document.querySelector("#main"));

See the Pen Hello World React by Sarah Drasner (@sdras) on CodePen.

Pretty straightforward, huh? It’s just like building blocks of any web page. We make the nav and the header, and apply these components to the app component, which is rendered on the body. The only real gotcha of this last example would be the strange extra div you see around <Header /> and <Nav />. This is because we must always return a single element. We can’t have two sibling elements, so we wrap them in a single div.

Now that you understand the building blocks, you can probably pretty easily piece together a page using React and React components. I’d suggest refactoring a page layout you’ve already made just to learn. Throw the stylesheet in there, and piece out the rest bit by bit until you’ve reconstructed its bones. It’s great practice.

There is a way to automate this process, but I would not suggest using a tool like this until you have already gone through the steps of building things out for yourself first. That way if you run into problems down the line, you know what’s going on.

The Usual Suspects: Variables & Event Handling

Let’s do some small event handling and put in some simple variables first just to see how that goes.

Consider the first demo again (we’ll use this throughout the article):

See the Pen Baby’s First React Attempt by Sarah Drasner (@sdras) on CodePen.

The blog post component has some pretty simple markup, so let’s start with that:

// Blog Post
var Post = React.createClass({
  render : function() {
    return (
      <div className="blog-post">
        <h3 className="ptitle">{this.props.ptitle}<small>{this.props.date}</small></h3>
        <img className="thumbnail" src={this.props.pimg} />
        <p>{this.props.postbody}</p>
        <div className="callout callout-post">
          <ul className="menu simple">
          <li>Author: {this.props.author}</li>
          <li>Comments: {this.props.comments}</li>
          <li>Tags: {h.getTaggedName()}</li>
          </ul>
        </div>
      </div>
    )
  }
});

Let’s add an arbitrary variable and event handler to see how that works. First thing to think about is that if we’re using JSX, curly brackets will let React know that we’re ready to use some JavaScript. Therefore our variable will look like {var}.

We’re going to add the variable statement inside the render function call, but before we return the markup. We can then access it by calling the variable, in this case, {com}. The click event is an inline onClick handler, which probably goes against best practices you’re used to. This is a name we chose, whereas render is a framework method. We call {this.tryClick}, and write a method stored as tryClick (an arbitrary name) within the same component, like so:

// Blog Post
var Post = React.createClass({
  tryClick : function() {
    alert('just trying out click events lalala');
  },
  render : function() {
    var com = "Comments";
    return (
      <div className="blog-post">
        <h3 className="ptitle">{this.props.ptitle}<small>{this.props.date}</small></h3>
        <img className="thumbnail" src={this.props.pimg} />
        <p>{this.props.postbody}</p>
        <div className="callout callout-post">
          <ul className="menu simple">
          <li>Author: {this.props.author}</li>
          <li>{com}: {this.props.comments}</li>
          <li>Tags: {h.getTaggedName()}</li>
          </ul>
        </div>
      </div>
    )
  }
});

The syntax for events in React begins with “on” and is camelCased. For example:

  • click = onClick
  • mouseEnter = onMouseEnter
  • keyPress = onKeyPress

You can find a full list of all the supported events.

Combining React and Other Libraries (Greensock, in this case)

I love GSAP for animation. You can use other libraries within React, so let’s combine GSAP and React and see how that goes.

We want to access other libraries at the correct time, so we have to make sure they are called immediately after the first render method. The method we use for this is called componentDidMount. We’ll explain a little more about other lifecycle methods further on, but what you need to know right now is this method is called immediately after the component is inserted into the document.

If you’re used to jQuery, you’re familiar with grabbing elements right out of the DOM. In this case, even though we are tweening DOM elements, we’re going to use React’s getDOMNode() instead of just grabbing them. You’ll also see that we’re actually calling the function to tween in the app component, and simply passing it down to our boxes. (You may have to hit rerun to see the animation.)

See the Pen 794b375a8725b039483c83fb63a4bd5a by Sarah Drasner (@sdras) on CodePen.

// App
var App = React.createClass({
 componentDidMount: function() {
    var sq1 = this.refs.first.getDOMNode();
    var sq2 = this.refs.second.getDOMNode();
    var sq3 = this.refs.third.getDOMNode();
    var sq4 = this.refs.fourth.getDOMNode();
    var sq5 = this.refs.fifth.getDOMNode();
    var allSq = [sq1, sq2, sq3, sq4, sq5];
   
    TweenLite.set(allSq, {css:{transformPerspective:400, perspective:400, transformStyle:"preserve-3d"}}); 

    TweenMax.to(sq1, 2.5, {css:{rotationX:230, z:-600}, ease:Power2.easeOut}, "+=0.2");
    TweenMax.to(sq2, 2.5, {css:{rotationY:230, z:-150}, ease:Power4.easeOut}, "+=0.2");
    TweenMax.to(sq3, 2.5, {css:{rotationX:500, z:150}, ease:Power2.easeInOut}, "+=0.2");
    TweenMax.to(sq4, 2.5, {css:{rotationY:500, z:-150}, ease:Power4.easeOut}, "+=0.2");
    TweenMax.to(sq5, 2.5, {css:{rotationX:1000, z:100}, ease:Power2.easeOut}, "+=0.2");
 },
 render: function() {
   return (
     <div className="scene">
        <Box ref="first"></Box>
        <Box ref="second"></Box>
        <Box ref="third"></Box>
        <Box ref="fourth"></Box>
        <Box ref="fifth"></Box>
    </div>
   )
 }
});

// Box
var Box = React.createClass({
  render: function() {
    return (
      <div className="squares"></div>
    )
  }
});
 
ReactDOM.render(<App/>, document.querySelector("#main"));

You may be used to accessing the DOM through jQuery or vanilla JavaScript. We can still do so, but here we’re accessing pieces of the DOM through getDOMNode() and refs, on this line: var sq1 = this.refs.squares1.getDOMNode();. You can read a little more about this in the React docs.

There are more React-specific ways to include motion in your projects- a really great one is Cheng Lou’s React-Motion and another good mention is React-GSAP-Enhancer.

Creating a Global Helper Function

You can even write helper functions that can be accessed by multiple components easily. We would use these with the same dot notation that we used with this.functionName. We store the helper function (in this CodePen demo we will do so at the start of the file, but in real applications, they would be stored in a separate file) and declare each function as an object the same way you do within the component structure.

Something like the correctly formatted date in the first demo with the blog posts would be:

var h =  {
  getTime: function() {
     var month = ["jan", "feb", "march"]; // …. and so on
     var d = new Date();
     var mon = month[d.getMonth()];
     var day = d.getDate();
     var year = d.getFullYear();
     var dateAll = mon + " " + day + ", " + year;
   
     return dateAll;
  }
};

And used like so: {h.getTime()}

The Good Stuff: Managing State

Ok! Now that we have the building blocks down, let’s get to some of the cool stuff.

React is surely good at building apps with easy-to-understand bite sized components, but what it’s really good at is managing state for these components. Let’s dive into that a little.

For this part, we’re going to go over two pretty key parts of understanding how to access and work with things that change.

  1. The first is state. The component itself possesses it, which means that it’s scoped to the component, and we will refer to it like this {this.state.foo}. We can update state by calling this.setState().
  2. The second is refers to how we pass read-only data along from the parent to the component (think like app is the parent to header in the first example). We refer to this as props, as in property, and will use it directly in the components with {this.props.foo}. This data can’t be changed by its children.

Any time we change either of these two things and our component relies on it, React will re-render the pieces of your component that it needs to.

The beauty of the virtual DOM is that React figures out only which DOM Nodes need to be updated.

I’ve read a bunch on state now, but I think Wes said it the most clearly so I’m going to paraphase him: if you’re used to jQuery, you’re storing all of your data in the DOM. React avoids this entirely by by storing the data in an object (state), and then rendering things based off the object. It’s like one big master that everything is based off of.

Trying Props Out

Let’s try just this.props first, we’ll add {this.props.title} to the Header component, and then we can access it within the app. We’ll add a string to create the title:

// App
var App = React.createClass({
  render: function() {
    return (
      <Header greeting="Hello, world!" />
    )
  }
});
 
// Header
var Header = React.createClass({
  render: function() {
    return (
      <div className="foo">
        <h1>{this.props.greeting}</h1>
      </div>
    )
  }
});
 
ReactDOM.render(<App/>, document.querySelector("#main"));

We can also add a default for props, in the aptly named getDefaultProps lifecycle method. This is great because sometimes you don’t want to have to specify props for every component. An example of this would be a default profile avatar if the user hasn’t set one yet, like the egg on Twitter, or setting a list to be an empty array which will be filled up later.

var ProfilePic = React.createClass({
  getDefaultProps: function() {
    return {
      value: 'twitter-egg.jpg'
    };
   ...
});

Doin’ Stuff

Now let’s build off of that to work with state a little. If we’re going eventually change this.state, we have to get it ready. To do so, we’ll use getInitialState, which lets us define what the state is at the get-go. We can’t add state without this.

Let’s just change the background based on user selection.

See the Pen 928579628fd2ecb0f98aff9c08774e93 by Sarah Drasner (@sdras) on CodePen.

// App
var App = React.createClass({
  /*setting state*/
  getInitialState: function() {
    return {
      bgColor: "teal"
    };
  },
  /*changes state*/
  handleColorChange: function (color) {
    // when we set state directly, react doesn't know
    // about it. that's why we use setState
    this.setState({ bgColor: color });
  },
  /*for the lifecycle methods*/
  updateBackgroundColor: function () {
    var body = document.querySelector('body')
    body.style.background = this.state.bgColor
  },
  /*lifecycle methods*/
  componentDidMount: function () { 
    this.updateBackgroundColor()
  },
  componentDidUpdate: function () { 
    this.updateBackgroundColor()
  },
  render: function() {
    return (
    /* by calling the title here on the component, we can access this.props on header */
      <div className="foo">
        <h1>Hello, World!</h1>
        <label>What color?
          <ColorPicker value={this.state.bgColor} onColorChange={this.handleColorChange}/>
        </label>
      </div>
    )
  }
});

// ColorPicker component
var ColorPicker = React.createClass({
  propTypes: {
    value: React.PropTypes.string.isRequired,
    onColorChange: React.PropTypes.func
  },
  handleChange: function(e) {
    e.preventDefault();
    var color = e.target.value
    
    // If whoever rendered us (the ColorPicker) is interested
    // when the color changes, let them know
    if (this.props.onColorChange)
      this.props.onColorChange(color);
  },
  render: function() {
    return (
      <select value={this.props.value} onChange={this.handleChange}>
        <option value="orangered">orangered</option>
        <option value="teal">teal</option>
        <option value="orange">orange</option>
        <option value="indigo">indigo</option>
        <option value="red">red</option>
      </select>
    )
  }
});

ReactDOM.render(<App/>, document.querySelector('#main'));

An important part of this to consider is that we need the handleChange function.

In regular DOM life, native selects would not require you to do something like this because it would automatically be updating to the users selection. In React all of the state is being managed by the component, so if you need an input or a select to listen for changes, you have to write it. This means that the component is in charge of the state, not the user.

This may seem like a lot of work for a small amount of reward, but we’ve purposefully kept these examples pretty slim. The cool parts of React really come in when you’re dealing with a lot of complexity. As much as I love jQuery (and I still do love jQuery, it’s not a boolean), you have to perform checks pretty frequently when something is changing. React solves this by removing this need because of the simplicity of the direction of data-flow, which also makes it easier in highly complex applications to reason about.

State Concepts

So now that we have the very basics down, let’s take a look really quickly at why we’re doing what we’re doing, as well as some best practices.

React works the best when we are updating states and rerendering the lower-level components. Fundamentally, we want these components to be mostly stateless, and receive data from the higher-level components. The components at the top of our hierarchy, like our app, work best when they are mostly stateful. That way they manage most of the interaction logic and pass state down using props. That said, there still will be times where each component will have it’s own state. It’s important to remember, though, that siblings shouldn’t talk to eachother directly, they should talk to their parent component.

Therefore, we want to keep the state in the component as much as we possibly can. You don’t ever actually have to worry about when stuff gets rendered. All you need to worry about is when state changes, and React takes care of rendering for you.

That kind of best practice ideology leads directly to why I’ll also advise you to not use props in getInitialState, and there’s more information here on why this is considered an anti-pattern.

We don’t want to abuse state too much. The rendering of the components is pretty fast, but performance can sink if you begin to try to manage too much state. There are some ways to get around this once it’s actually a problem, but best bet just to not get in that predicament to begin with.

The rest of this article is about how to best manage these states and keep the immutable concerns higher in the hierarchy, while still referencing our stateless components lower down.

Refs

We can also access information about the element with something called ref. We use refs by attaching it to any component. It is then returned during the render() method, and we can then refer to it outside of the render() method. This is incredibly useful.

Consider the first Pen again. Let’s think for a minute how we’re making these new blog posts, and use refs while doing so.

In each form input we have a ref, like:

<input type="text" ref="name" placeholder="Full Name required" required />

On the form element itself, we call:

onSubmit={this.createPost}

which references the createPost function above the render function, and uses refs to store information from that submission:

var post = {
 name : this.refs.name.value,
 ...
}

and then we have a way to refer to it in the app state using this.props:

this.props.addPost(post);
refs-overview

That’s pretty handy because now we have a variable post, with objects that are storing its name (shown here), date, details, and so on. We still haven’t stored any of this in the App state yet, we’ve only created a way for App to use it. Let’s go over that next, along with keys.

I’ve used this example as a way of talking about refs in general, but in real-life applications, you might want to consider using something like form-serialize to serialize form fields to submit over AJAX.

Keys and Using Refs

In our last section we made a way to store the data we collected in the form without passing it off. That’s because in React, we want to manage this state in the top-level of our hierarchy. In order to store this state, we’re starting up our initial state with an empty object. That’s where we’ll eventually store our post data.

getInitialState : function() {
  return {
    posts: {}
  }
},

Then we have our addPost function. Note that we’re managing this here instead of on the form, even though we called it from the form. We’re giving the state a timestamp to keep the posts unique and also setting the state for the posts.

addPost: function(post) {
  var timestamp = (new Date()).getTime();
  // update the state object
  this.state.posts['post-' + timestamp] = post;
  // set the state
  this.setState({ posts : this.state.posts });
},

Each child in an array should have a unique key.prop. This is important because React will reuse as much of the existing DOM as possible. React uses keys to keep track of which elements in the DOM it should update. It keeps us from having to redraw all of the DOM elements when we rerender. That helps the performance of our app.

Now let’s take a look at the App again, and see what we do with our newly stored data from the form:

// App
var App = React.createClass({
  getInitialState : function() {
    return {
      posts : {}
    }
  }, 
  addPost : function(post) {
    var timestamp = (new Date()).getTime();
    // update the state object
    this.state.posts['post-' + timestamp] = post;
    // set the state
    this.setState({ posts : this.state.posts });
  },
  renderPost : function(key){
    return <NewPost key={key} index={key} details={this.state.posts[key]} />
  },
  render : function() {
   ...
    return (
      <div>
        <Banner />
	    ...
          <div className="list-of-posts">
              {Object.keys(this.state.posts).map(this.renderPost)}
          </div>
          <Submissions addPost={this.addPost}/>
        </div>
      </div>
    )
  }
});

You can see that when we render the app, we use the Object.keys to create a new array. We then use .map() with the renderPost function we made earlier. For those unfamiliar with .map(), it’s useful for creating an array out of an existing one, you can think about it like a loop.

<div className="list-of-posts">
  {Object.keys(this.state.posts).map(this.renderPost)}
</div>

Now let’s make that renderPost function we just called. We pass the key as a parameter and assign it as the key, the index, and create an object we’re calling details to hold information about the state of the posts.

renderPost: function(key) {
  return <NewPost key={key} index={key} details={this.state.posts[key]} />
},

It might seem odd that we pass a key and an index, but inside a component we are unable to access the key prop so we pass another one called index. This renderPost function is simply creating a <NewPost /> component for every item in our array, with details passed down that we can access. This is pretty awesome because it means that if something in our state updates, it’s propagating down and we can manage it in one spot.

Here’s the <NewPost /> component, where we use details handed down from app to render all of the information. You can see that helper function we made earlier used for the correctly formatted date used here as {h.getTime()}:

/*
  NewPost
  <NewPost />
*/
var NewPost = React.createClass({
  render : function() {
    var details = this.props.details;
    return (
      <div className="blog-post">
        <h3 className="ptitle">{details.title}<small>{h.getTime()}</small></h3>
        <img className="thumbnail" src={details.image} alt={details.name}/>
        <p>{details.desc}</p>
        <div className="callout callout-post">
          <ul className="menu simple">
          <li>Author: {details.name}</li>
          <li>Comments: 0</li>
          <li>Tags: {h.getFunName()}</li>
          </ul>
        </div>
      </div>
    )
  }
});
Keys Overview

See the Pen Baby’s First React Attempt by Sarah Drasner (@sdras) on CodePen.

All Together Now

Now that we understand keys, let’s take a look at the big picture for a minute. We discussed getInitialState, componentDidMount, and render, but there is one more mounting method for React. It’s called componentWillMount. It’s similar to componentDidMount, but it executes immediately before the component renders for the first time.

This diagram does not include everything that is available in React at all, but rather a glimpse at what we’ve covered thus far and enough to get you started playing around.

Conclusion

There’s a lot more than this article to learn about React, this is just the start. Hopefully this beginner’s journey gives others a little insight into how to get up and running. This post was 20 pages long and we didn’t even get to a ton of other important and related subjects, including but not limited to ES6, Browserify, Gulp, Webpack, or a myriad of alternative implementations.

For further learning, again, I highly suggest diving into Wes Bos’ course, and he’s offering a 10% discount to CSS-Tricks readers with the code CSSTRICKS, as well as watching some videos on Frontend Masters. Michael Jackson has a wonderful training course that you can register for (we’re having him come to Trulia in San Francisco in March! Stay tuned for sign ups). There’s also a great book by Artemij Fedosejev called React Essentials and this list that’s worth bookmarking by Artem Sapegin. It shouldn’t be understated that the React Docs are quite good resources. Happy learning!

Many thanks to Michael Jackson, Wes Bos, and Val Head for proofing this article.