React JS Tutorial and Guide to the Gotchas

Justin Deal
Justin Deal / February 26, 2015

If you haven't used React at all, you're in the right place. If you have used React, but you've run into some confusing edges, you're still in the right place. This guide covers all the basics as well as some of the confusing gotchas.

What is React and why should you use it?

The React home page answers the "what" pretty well. If you ask me, I'd define React as a "JavaScript-based UI rendering engine." Notice I left "HTML" out of that definition. That's because HTML is just one of many possible targets. I also left out "browser" because you can use React on the server as well. (And hopefully native apps soon.) The "engine" part of my definition reminds me of the similarity with game engines. With React, just like with a game engine, you simply specify how a given application state gets translated to a given view. If something changes, you don't change the view. Instead, you just render again and get a new view.

This simple approach makes a whole set of problems fall away. At Zapier, we're transitioning from Backbone views to React views, and there's no turning back at this point. With React, there's no extra complexity keeping your application state and view in sync. Just render, rinse, repeat. You can easily build completely isolated, reusable, and composable UI components. Nested views just become a natural extension of the way React works. If things change, refactoring views is almost fun!

Hello world

So let's get started!

All of these examples will use JSFiddle, so you can see them running right here in this post. Just click on the "Result" tab to see the example as it would appear in a browser. Follow the "Edit in JSFiddle" link if you want to hack on a particular example.

Okay, so the most minimal example possible:

Not very exciting. React is an extremely powerful tool, and we just used it to print boring old "Hello World!" But we're going to stop right here to talk a little about JSX.

JSX

If you've heard of React, you've probably also heard of JSX. And you could have any number of opinions about it. To prefer actually using JSX, a couple of things have to be true:

  • You have to understand what it actually is and all of its nuances.
  • You have to experience a use case where it's really necessary.

JSX is not a template language

The first thing to realize is that JSX is not a template language. If you confuse it with something like Handlebars, you'll end up thinking it's much ado about nothing. Worse, it will break in mysterious ways. JSX is simply an alternate JavaScript syntax, albeit one that is (at least currently) specific to React. The above example is identical to:

Of course, React.createElement itself is somewhat mystical, so let's try to clear that up a bit. When you use React, you usually don't deal with DOM elements directly. Instead, you create elements for a "virtual DOM". These elements are really nothing but JSON objects. They represent the underlying DOM structure but don't carry any of the weight of actual DOM elements. React converts these virtual elements into real DOM elements as necessary. React.createElement is just a method used to create these JSON objects. The signature is:

React.createElement(elementNameOrClass, props, children...)

For our Hello World example, we're using an element name that maps to HTML. In a bit, we'll start creating our own component classes, and you can pass those as the first parameter. The second parameter is used to pass properties to the component instance. The rest of the parameters become a special property children for the component. We'll talk more about these later. For now, just keep in mind that JSX is (roughly) doing this conversion:

  1. If the tag name is a string that maps to an HTML element, use the component class for that HTML element.
  2. If the tag name is not an HTML element, assume it is a local variable name that points to a custom component class.
  3. Attributes are converted into an object and passed as the second parameter.
  4. Child elements are passed as the remaining parameters.

As an example, here's some JSX:

<div id="greeting-container" className="container">
  <Greeting name="World"/>
</div>

This would be converted to:

React.createElement("div",
  {
    id: "greeting-container",
    className: "container"
  },
  React.createElement(Greeting, {name: "World"})
)

Handlebars, Django templates, and lots of other template languages are allowing you to alternate between plain text and some specialized template instruction language. The template language rarely has the expressive power of the host language. JSX is simply converting XML-like markup into JavaScript instructions. It's exactly as if you had typed in the corresponding JavaScript code.

This is awesome because you can use the full power of JavaScript and everything you've learned about expressions, functional composition, and any other goodies in your views. No need to write specialized helpers that are specific to your template language. Just use JavaScript! For example:

The braces let us use plain JavaScript, but this isn't exactly analogous to escaping back to the host language. Note inside our map function, we go back to markup, and then inside that nested markup, we go back to JavaScipt. This is a clear example of how JSX is not a template language.

JSX is totally optional but sometimes really useful

In my opinion, JSX is really useful for two reasons:

  • It provides useful shorthand for some React boilerplate that you would otherwise be forced to use.
  • It makes your HTML markup look like HTML markup.

The first is already pretty obvious from the examples above. The JSX examples are shorter than the corresponding JS examples. Of course, we could finesse our way around this. You may see code like this:

var R = React.DOM;
Greeting = React.createFactory(GreetingClass);

React.render(
  R.div({id: "greeting-container", className: "container"},
    Greeting({name: "World"})
  ),
  document.body
);

React.DOM gives you a bunch of factories for HTML elements. React.createFactory is just a helper that binds your component class to React.createElement so you can make your own factories. Unfortunately, you'll then have to juggle two things as sometimes you need the class vs. the factory. But the bigger problem in my opinion is just that the JavaScript version has hidden the markup. Look at this small bit of markup:

<p>
  The live example is the same. The only difference is that we
  render to <code>mountNode</code>, which is just the DOM node
  for the example.
</p>

It gets quite ugly when you turn that into JavaScript:

R.p({},
  'The live example is the same. The only difference is that we render to ',
  R.code({},
    'mountNode'
  ),
  ', ' +
  'which is just the DOM node for the example.'
)

The above example is the actual code that made me realize I should probably just use JSX.

If you have a designer working with HTML, it's not that much of a stretch to move to JSX. But replacing all the markup with that JavaScript is going to be painful and probably leave you with an angry designer.

Custom components

So far, I've explained this weird JSX thing, and I've explained how using JSX for your views (which is really just JavaScript) gives you a really powerful view language. But none of this is a good reason to use React. Once you start creating custom components though, there's no turning back.

Our first component

Let's try to make a note-taking app. To keep things simple, we're not going to worry about persisting any data to the server. To get started, let's keep things really simple and just statically define some data to render.

var notepad = {
  notes: [
    {
      id: 1,
      content: "Hello, world!\nBoring.\nBoring.\nBoring."
    },
    {
      id: 2,
      content: "React is awesome.\nSeriously, it's the greatest."
    },
    {
      id: 3,
      content: "Robots are pretty cool.\nRobots are awesome, until they take over."
    },
    {
      id: 4,
      content: "Monkeys.\nWho doesn't love monkeys?"
    }
  ]
}

Let's make a custom component and render a summary page of our notes. We'll just consider the first line of our note to be the title. (We're not going to concern ourselves with performance here.)

var NotesList = React.createClass({
  render: function () {
    var notes = this.props.notepad.notes;

    return (
      <div className="note-list">
      {
        notes.map(function (note) {
          var title = note.content.substring(0,
            note.content.indexOf('\n')
          );
          title = title || note.content;

          return (
            <div key={note.id} className="note-summary">
              {title}
            </div>
          );
        })
      }
      </div>
    );
  }
});

Note that a simple React component just needs a render method. There are lots of other methods available, but render is the main workhorse. In the render method, you just return what you want rendered. React takes care of it from there.

Note also that I snuck in a key attribute. The key uniquely identifies a component among its siblings. Generally, if you're using map or filter or producing an array of elements by any other means, you want to give each element a key. Sometimes with a single element, if it represents a unique thing, you also need to use a key to make sure React discards the DOM rather than re-using it. Later, we'll discuss why this is necessary. For now, just realize that React will complain with a warning if you don't do that. And if you ignore the warning, strange things will probably happen.

Putting it all together and rendering it:

Now things are getting interesting. If React could only render <div> and friends, it wouldn't be very useful. But you get to create your own components. Even better, the look and behavior of those components is completely controlled by the properties that are passed into it. The NotesList component in the above example acts much like a pure function. All of its state is passed in as props. If we later decide to support multiple notepads, this component is useful as-is. We just pass in the notepad we want to render, and the component does its thing. It's also easy to break the component apart later. Let's just go ahead and make the summary its own component.

var NoteSummary = React.createClass({
  render: function () {
    var note = this.props.note;
    var title = note.content.substring(0,
      note.content.indexOf('\n')
    );
    title = title || note.content;

    return (
      <div className="note-summary">{title}</div>
    );
  }
});

var NotesList = React.createClass({
  render: function () {
    var notes = this.props.notepad.notes;

    return (
      <div className="note-list">
      {
        notes.map(function (note) {
          return (
            <NoteSummary key={note.id} note={note}/>
          );
        })
      }
      </div>
    );
  }
});

Pretty easy, huh? Much like refactoring a function into smaller functions, you can just chop out a chunk and put it inside another component. Then just call your new component, passing in the appropriate props. Now we can use the NoteSummary component anywhere we want. If something goes wrong with the note summary, we know where to look. The error is either inside the component or in the props passed in to create it.

Reactive components

So that's all well and good for a dumb static page, but what about making our app do something, uh, react-ive? As the name implies, React has you covered.

If your app's state has changed, just re-render your app

Let's say that again. If anything, anywhere in your app has changed, throw the whole thing away and re-render the whole thing.

Seriously?

Yes, seriously.

Eventually, you could reach some non-performant edges, but with React, you have to push pretty hard to hit those edges. Just forget any of your old jQuery habits where you respond to an event and then tweak the DOM. Forget any complicated two-way binding and watching scopes in Angular. When you have a new app state, just re-render the new app state.

So let's make it possible to add notes. For this simple example, we'll add some functions at the top-level to handle user events. We're going to keep our components isolated by passing in those handlers. In a real app, you might want to use something like Flux, which is a pattern for using events in a tightly controlled manner. If you're using something like Backbone, you can also get by using your existing models and passing those into your components.

Let's wrap our render so we can call it every time there's a change. We're also passing in a handler to add notes and one to change notes, which we'll define in a minute.

var onChange = function () {
  React.render(
    <Notepad notepad={notepad} onAddNote={onAddNote}
      onChangeNote={onChangeNote}/>,
    document.body
  );
};

onChange();

Any time there's a change, we're going to call onChange which will re-render the state of our app. Again, don't worry about performance. This is all done with the magic of the virtual DOM. React will intelligently decide what DOM elements stay and go. If exactly the same DOM elements are required for a re-render, it will keep them and just tweak attributes and content as necessary.

Also, as long as you use proper keys where necessary, you don't have to worry about an input losing focus. If you've ever used Backbone in this manner, wiping out the DOM and starting over, you know that when an input gets removed and put back, it loses focus, which is frustrating for the user. With React, if you re-render the same element, the corresponding DOM element will remain, so the user can happily keep typing, even if the typing is causing the DOM to change.

Now let's add that handler for adding notes. We'll get rid of our static notes, add an ID mechanism, and keep track of the currently selected note.

var notepad = {
  notes: [],
  selectedId: null
};

var nextNodeId = 1;

var onAddNote = function () {
  var note = {id: nextNodeId, content: ''};
  nextNodeId++;
  notepad.notes.push(note);
  notepad.selectedId = note.id;
  onChange();
};

Let's also add a handler for changing those new notes.

var onChangeNote = function (id, value) {
  var note = _.find(notepad.notes, function (note) {
    return note.id === id;
  });
  if (note) {
    note.content = value;
  }
  onChange();
};

Again, we're keeping things simple here. In a larger app, we'd want to do something more sophisticated. The principal will remain the same though. Our components will have some mechanism for notifying that the user has changed something. When there's a change, we'll have some mechanism to re-render the app. Our component will never be the source of truth for data that is persisted. That data always lives outside the component. When our source of truth has decided there is a change, our components simply re-render that new truth.

Let's create a component for editing notes.

var NoteEditor = React.createClass({
  onChange: function (event) {
    this.props.onChange(this.props.note.id, event.target.value);
  },

  render: function () {
    return (
      <textarea rows={5} cols={40}
                value={this.props.note.content}
                onChange={this.onChange}/>
    );
  }
});

This component receives an onChange handler, which it will use to pass along changes to the note.

We'll create a new Notepad component that will render the list of notes, a button to create a new note, and an editor to edit a note.

var Notepad = React.createClass({
  render: function () {
    var notepad = this.props.notepad;

    var editor = null;

    var selectedNote = _.find(notepad.notes, function (note) {
      return note.id === notepad.selectedId;
    });

    if (selectedNote) {
      editor = <NoteEditor note={selectedNote}
        onChange={this.props.onChangeNote}/>
    }

    return (
      <div id="notepad">
        <NotesList notepad={notepad}/>
        <div>
          <button onClick={this.props.onAddNote}>Add note</button>
        </div>
        {editor}
      </div>
    );
  }
});

Let's try it out:

Type in a new note and notice that the summary title changes as you type. This app is awesome because:

  1. Our components don't have to concern themselves with the state of the app. That all exists separate from our views, as it should.
  2. Our components don't have to worry about the state of the DOM. They just provide fresh elements to render, and React magically manipulates the DOM. We just render, throw away, and repeat.
  3. Our components are just like pure functions. We feed in the current state, and they simply reflect that state.

In a larger app, that third point might get out of hand. Passing in callbacks through a deeply nested hierarchy can get a bit unwieldy. It's outside the scope of this tutorial, but Flux is the oft-cited solution to this problem. Where possible though, follow the simple model of passing in callbacks, and your code will be a lot more portable.

Let's go ahead and add a handler to select a note.

var onSelectNote = function (id) {
  notepad.selectedId = id;
  onChange();
};

We'll pass in this handler to our Notepad component.

var onChange = function () {
  React.render(
    <Notepad notepad={notepad} onAddNote={onAddNote}
      onSelectNote={onSelectNote}
      onChangeNote={onChangeNote}/>,
    document.body
  );
};

Then we can just pass this through our Notepad component.

var Notepad = React.createClass({
  render: function () {
    var notepad = this.props.notepad;

    var editor = null;

    var selectedNote = _.find(notepad.notes, function (note) {
      return note.id === notepad.selectedId;
    });

    if (selectedNote) {
      editor = <NoteEditor note={selectedNote}
        onChange={this.props.onChangeNote}/>
    }

    return (
      <div id="notepad">
        <NotesList notepad={notepad}
          onSelectNote={this.props.onSelectNote}/>
        <div>
          <button onClick={this.props.onAddNote}>Add note</button>
        </div>
        {editor}
      </div>
    );
  }
});

In our NotesList component, we'll respond to clicks to a summary and call the callback. We'll also style the selected item a bit.

var NotesList = React.createClass({
  render: function () {
    var notepad = this.props.notepad;
    var notes = notepad.notes;

    return (
      <div className="note-list">
      {
        notes.map(function (note) {
          return (
            <div key={note.id} className={
              notepad.selectedId === note.id ? 'note-selected' : ''
            }>
              <a href="#" onClick={
                this.props.onSelectNote.bind(null, note.id)
              }>
                <NoteSummary note={note}/>
              </a>
            </div>
          );
        }.bind(this))
      }
      </div>
    );
  }
});

Now you can try it out.

Clicking on a title in the list should now let you edit the note. Yay! Our app is getting more complex, but our individual components are remaining pretty simple. At any time, if you feel like a component is getting out of hand, just split it up.

Transient state

Sometimes a component needs to keep track of some state, but it isn't really application state. Let's say we want to add the ability to delete a note. And we want to confirm before deleting. We don't really need to persist the fact that you're in the middle of deleting. We can just throw away that state. So we want our component to just hold onto that state rather than maintaining it externally. React has a powerful mechanism for setting and using this internal state.

Let's first add a delete handler and wire it up without the confirmation. Same steps as before. We add a delete handler. We pass it through. We hook the onClick for a button up to the handler. Now you can delete notes!

In this case, the delete button is part of the note editor. The same principles apply if you wanted to add it to the summary list.

Our note editor without the confirmation is this:

var NoteEditor = React.createClass({
  onChange: function (event) {
    this.props.onChange(this.props.note.id, event.target.value);
  },

  render: function () {
    return (
      <div>
        <div>
          <textarea rows={5} cols={40}
            value={this.props.note.content} onChange={this.onChange}/>
        </div>
        <button onClick={
          this.props.onDelete.bind(null, this.props.note.id)
        }>Delete note</button>
      </div>
    );
  }
});

To make it stateful, we need to use two things. The getInitialState method allows us to provide an initial state for our component, and the setState method lets us change the state of our component. Any time we call setState, a re-render will automatically occur. Note that setState is asynchronous though. The re-render will occur when React decides it's ready. In modern browsers, this will generally happen no less than 1/60 of a second later. (Modern browsers render 60 times per second, and React hooks into this via requestAnimationFrame.)

Here's the same component with a confirmation:

var NoteEditor = React.createClass({
  getInitialState: function () {
    return {
      isConfirming: false
    };
  },

  onChange: function (event) {
    this.props.onChange(this.props.note.id, event.target.value);
  },

  onDelete: function () {
    if (this.state.isConfirming) {
      this.props.onDelete(this.props.note.id);
      this.setState({isConfirming: false});
    } else {
      this.setState({isConfirming: true});
    }
  },

  onCancelDelete: function () {
    this.setState({isConfirming: false});
  },

  render: function () {
    return (
      <div>
        <div>
          <textarea rows={5} cols={40}
            value={this.props.note.content}
            onChange={this.onChange}/>
        </div>
        <button onClick={this.onDelete}>
        {
          this.state.isConfirming ? 'Confirm' : 'Delete note'
        }
        </button>
        {
          this.state.isConfirming ? <button onClick={this.onCancelDelete}>Cancel</button> : null
        }
      </div>
    );
  }
});

We use the getInitialState to set isConfirming flag to false. We then intercept the delete handler rather than just passing it through. If we're confirming, we go and delete, otherwise, we set the isConfirming flag to true. In our render method, we also render a cancel button so that we can set the isConfirming flag back to false.

It's also a good idea to give a key to our editor.

editor = <NoteEditor key={selectedNote.id} note={selectedNote} onChange={this.props.onChangeNote} onDelete={this.props.onDeleteNote}/>

This way when we switch to editing a different note, React removes the component, and we don't end up with state from a different note.

Lifecycle methods

Sometimes you want to do something when a component is added to or removed from the DOM. For this, React provides lifecycle methods. There are other lifecycle methods as well, for example, responding when the properties change for a component.

Let's implement a Pulse component. It's something like the old blink tag but just slightly less obnoxious. We'll use it to wrap our confirm button so it's really obvious.

var Pulse = React.createClass({
  getInitialState: function () {
    return {
      opacity: 1.0
    };
  },

  componentDidMount: function () {
    this.timer = setInterval(function () {
      var opacity = this.state.opacity;
      opacity -= .05;
      if (opacity < 0.5) {
        opacity = 1.0;
      }
      this.setState({
        opacity: opacity
      });
    }.bind(this), 100);
  },

  componentWillUnmount: function () {
    clearInterval(this.timer);
  },

  render: function () {
    return (
      <span style={{opacity: this.state.opacity}}>
      {this.props.children}
      </span>
    );
  }
});

There are a few things to note here.

  1. We use getInitialState again to set an initial opacity state.
  2. We hook into componentDidMount to do something when the component is added to the DOM. Here, we set this.timer to an interval timer that will decrease the opacity to 50% and then bump it back up to 100%.
  3. We hook into componentWillUnmount to clean up our timer.
  4. We render using the opacity in the state.

We'll then use the Pulse component around our confirm button like this:

this.state.isConfirming ?
  <div>
    <Pulse>
      <button style={{color: 'red'}}
        onClick={this.onDelete}>Confirm</button>
    </Pulse>
    <button onClick={this.onCancelDelete}>Cancel</button>
  </div> :
  <button onClick={this.onDelete}>Delete note</button>

See it here in all its glory.

This pattern is often useful for listening to events. (In fact, it's how Flux works.) Just listen to the event when the component is mounted. Set the state when the event happens, and the component gets re-rendered. Clean up before the component is unmounted.

Rules to follow

So now you're a React expert, eh? Hold on. The nice thing about React is that there really are only a few core concepts to learn. Once you know how to build your own components, you're not going to get hit with any huge surprises where you realize you were fooled all along. However, there are some nuances that you need to be aware of to avoid confusion.

Understand the virtual DOM terminology

Most of the virtual DOM can be treated like magic, and you can ignore the implementation. You do want to at least nail down the terminology though. I recommend Sebastian Markbåge's gist on React DOM Terminology which describes things in detail. I've been using most of that terminology in this post, but that wiki page will clarify things further.

Also, know that the terminology has changed a bit since earlier versions of React. So older blog posts may call things by different names.

Don't mutate anything in your render method

Your render method represents the view at a particular moment in time. For React to do its job properly, you need to hand it some data and let it render the whole thing before changing anything. Since you'll be re-rendering every time there's a change, you can't go changing something while you're rendering. It's like asking someone to paint your picture, and then trading places with your grandmother halfway through. That artist is going to look at you funny. Similarly, React will complain about any funny business. Or even worse, if you manage to sneak in the mutation, you will probably get really weird, confusing results.

Don't expect children to always be an array

Remember this.props.children above? We just used it in our Pulse component. In that case:

render: function () {
  return (
    <span style={{opacity: this.state.opacity}}>
    {this.props.children}
    </span>
  );
}

We just passed it through to the span component. However, imagine we wanted to do something with each child. So we'd do something like this:

render: function () {
  return (
    <span style={{opacity: this.state.opacity}}>
      <ul>
      {
        this.props.children.map(function (child) {
          return <li>{child}</li>;
        });
      }
      </ul>
    </span>
  );
}

Then we could use it like this:

<Pulse>
  <div>Moe</div>
  <div>Larry</div>
  <div>Curly</div>
</Pulse>

And so far, all is well. But what if you use it like this:

<Pulse>
  <div>Joe</div>
</Pulse>

Seems like that should work fine, right? Unfortunately, no. In that case, React will send you a single element for this.props.children. So you'll get an error because that element won't have a map method. If you always want to treat it like an array, you'll have to coerce it to an array first. A bit of a pain, but it saves React from unnecessarily creating array garbage in the passthrough case.

Also, if you do this:

<Pulse></Pulse>

this.props.children will be undefined, since nothing was passed at all.

Know the difference between controlled and uncontrolled components.

This one is a bit tricky. It's in the React docs, but I was confused even after reading that. For editable form elements (like <input> and <textarea> and <select>), you can pass the value two different ways.

If you pass in a value prop, then that form element will have that value no matter what the user enters. In that case, it's a "controlled" component, meaning that you are controlling the value. So if you pass in the value of "jo" and that user adds an "e" to make that "joe", you have to subsequently set the value to "joe". Otherwise, the value will remain as "jo". This is generally a good thing, because it means that you'll visually see that your application state is holding the same value as the DOM elements.

If you pass in a defaultValue prop, the form element will initially show that value, but after that, no matter what value you pass in, the value displayed will be whatever the user last typed in.

In general, you probably want to stick with controlled components. But if you are creating an old school form where the user is just going to submit it, then uncontrolled components are fine. Also if you may have some invalid transient states, you may want to use an uncontrolled components. Personally, in that case, I prefer to use transient state to hold the value and still use controlled components.

Mind your async

In the sample app above, we never did any asynchronous loading, but of course in the real world, you will. If you're making a small app, it's probably okay for your component to do some asynchronous work. In that case, do that work inside a componentDidMount method just like we did with our setTimeout. When your async function returns, just do a setState to cause a re-render. This means that you'll need some intelligent "zero state" view for before you have any data. This could just be a simple spinner or whatever.

When the user subsequently does some action, then you'll just intercept the event and do some async work. However, be very careful that you don't end up with inconsistent results. For example, if you fire an async request every time a key is pressed, some of those requests could return out of order and leave you with inconsistent results. React may happily roll something back to an old value if you tell it to do that with a setState.

In larger apps, I recommend getting async work out of your components and pushing it into a dark corner. The more your components behave synchronously, the easier it will be to reason about their correctness and debug them. Doing async work is probably making them do work that is unrelated to their purpose as views.

If you do use React for async work, it's at least a good idea to push that work to top-level components so that your child components can be easily reusable.

Virtual DOM is not shadow DOM

Once in a while, I hear people say they understand the virtual DOM because they think it's the same as the shadow DOM. These are in no way related.

Some HTML attributes are different in JSX

When you use <div>, <span>, and other HTML elements, you can mostly treat them like their HTML equivalents. But some attributes are different. Some notable differences:

If you have a big block of HTML that you want to translate to JSX, you can use
this compiler service.

Keys are defined in parent components, not in child components

Note in this example:

var StoogeList = React.createClass({
  render: function () {
    return (
      <ul>
      {
        this.props.stooges.map(function (stooge) {
          return <Stooge key={stooge.id}/>;
        });
      }
      </ul>
    );
  }
});

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

StoogeList has to specify the keys of each of its children. The Stooge component doesn't need to worry about keys at all, because it's only rendering a single element.

Keys have to be at the top of the child

If we refactor the example above to this:

var StoogeList = React.createClass({
  render: function () {
    return (
      <ul>
      {
        this.props.stooges.map(function (stooge) {
          return <li key={stooge.id}><Stooge/></li>;
        });
      }
      </ul>
    );
  }
});

var Stooge = React.createClass({
  render: function () {
    return <div>{this.props.stooge.name}</div>;
  }
});

Note that we had to move the key from <Stooge> to <li>. This is often a source of mistakes, where the structure is changed, but the key has been left in a nested element.

JSX attributes are not JSON

This is a mistake I often make:

render: function () {
  return <div style={fontWeight: 'bold'}></div>
}

See the problem? It should actually be:

render: function () {
  return <div style={{fontWeight: 'bold'}}></div>
}

You need one set of braces to get back to JavaScript and then another to make your object.

Optimize later!!!

Build your app with the assumption that it will run buttery smooth with no optimizations. A lot of times, that assumption will be correct. In modern browsers, JavaScript is very fast, and the DOM is very slow. React is taking care of the second half of that equation, so don't worry too much about what remains: your JavaScript code. React gives you the flexibility to easily refactor, but once you start coding in weird optimizations, that gets harder. And caching for no reason will cause bugs for no reason.

If you really do run into nasty performance problems, first take a step back and make sure the solution makes sense for the user. Sometimes if React is drowning, then your users may be drowning in a bad UI also.

If you really do need to squeeze out some performance, then you can look at shouldComponentUpdate. That's definitely outside the scope of this post, but that's a hook you can use to say "hey, React, nothing has changed here, so don't bother re-rendering."

Where to go from here

If you want to hack out your own fiddles, you can fork the JSX base fiddle.

If you need some info on using React in your own project, the React docs can help you out with that.

Now go build something using React!

And if you're interested in working on React at Zapier we'd love to have you consider joining the team.


Load Comments...

Comments powered by Disqus