If you’ve been following this blog you’ve probably heard me talk about using React with Meteor before.

A common misconception about React is that it’s hard to learn. It’s not! So let me show you how if you already know JavaScript, you too can learn enough React to build Meteor apps in less than 15 minutes.

Table Of Contents

Components

Everything in React is a component. Same thing as templates really, but you have to admit “component” sounds a lot cooler.

Here’s how you define a React component:

You’re now able to use that component by calling <Post/> in any other React component, or from React Layout.

A Note About Classes

When reading React code, you’ll often see the more modern ES2015 class syntax used to declare components. But to keep things simple, I’ve decided to use the “regular” JavaScript syntax here.

JSX

Wait what?! Waiter, there’s some HTML in my JS!

Don’t panic, this is perfectly normal. React uses a special .jsx file format that lets you put HTML tags right in your JavaScript. This will seem weird at first but trust me, you’ll get used to it pretty quickly.

Since JSX is still JS, you can easily use JS variables and syntax right in there by using curly brackets:

Three things you need to know about writing HTML in JSX:

  • Any JSX fragment always needs to be wrapper by a single outer tag (in this case <div>).
  • You need to use className instead of class, since class is a reserved JavaScript keyword.
  • If you need to return more than one line of HTML, you can wrap it in a (...) block.

Using Collection Data

Now you’ll probably want to load your post title and body from your Mongo collections. You can do that using the ReactMeteorData mixin and its getMeteorData function, which returns an object accessible as this.data from anywhere in your component:

This is one of the key differences between Blaze and Meteor: whereas Blaze lets you pepper reactive calls like Collection.find(), FlowRouter.getParam('postId'), Session.get(), etc. throughout your template code, React requires you to centralize them all in one place first.

getMeteorData is the only reactive context in a React component, so that’s where we put all our reactive stuff.

Mixins Are Dead?

It would seem like React mixins are on their way out, and in fact Meteor will be moving away from them soon as well.

Still, for now the ReactMeteorData mixin works, so until a better alternative comes along officially it’s probably safe to use it.

Props

What if you don’t want to retrieve that postId parameter from the URL, but instead want to pass it on from another component? This is where props come in:

props is an object that contains whatever attributes are passed to the component when included from somewhere else (i.e. <Post postId="foo"/>). Here’s a nice tip, you can also validate each props and optionally mark it as required (meaning the component will throw an error if it’s not provided):

State

Unlike props, which are passed from another component, the state (accessible as this.state) contains variables relevant to the internal state of your component. A good use case for state would be keeping track of a dropdown menu’s open and closed state, or a data table’s sorting options.

You probably won’t need to worry about using state in the beginning, so just pretend it doesn’t exist for now.

Functional Stateless Components

One reason to avoid using state is that this lets you turn your components into functional stateless components.

In essence, these are “dumb” components that just take in some properties and spit out some HTML, and they make your code a lot simpler.

Component-Level Subscriptions

With any large enough Meteor apps, you’ll eventually run into cases where you want to subscribe to data at the component level. It’s as easy as adding a Meteor.subscribe() call in your getMeteorData function:

While the subscription is still loading, Posts.findOne(postId) will return undefined and we’ll see our loading message. Then, once the subscription is ready, React will automatically re-render the component with the correct content. This works because getMeteorData is a reactive context, meaning it’ll re-run as the subscription updates.

Using jQuery

Generally speaking, you should avoid going behind React’s back to modify the DOM. Still, sometimes you need to do something outside of React once the component is loaded, such as triggering some kind of cool jQuery plugin.

You can do this using componentDidMount, which will run once React has done its thing and loaded the component into the actual DOM:

Events

Let’s see how to handle events, such as clicking an “upvote” button:

Note how I’m using this.upvote and not this.upvote()? This is because I just want to pass a reference to the upvote function to the onClick event handler, not actually run the function (yet).

Splitting Components

At the end of the day, JSX is just basically JavaScript. As such, JSX doesn’t have a special “embed” or “include” syntax, but instead has you call regular JavaScript functions. For example, this is how we’d split out our “upvote” button into its own little function:

This time we’re not passing this.renderUpvoteButton to a handler or another function, and we do want to execute it to render out its contents.

Conditionals

Since JSX sticks closely to JS, it doesn’t provide fancy {{#if}}s and {{#each}}s like templating languages. Instead, you just use plain old JS syntax and variables.

This is a little annoying at first, but you quickly learn to organize your code in a way that minimizes the need for ifs.

For example, let’s say we want to only show that <p> tag if our post contains a body property. The “dumb” way to do this would be to simply have two return blocks:

But we can simplify our code greatly by using JavaScript’s ternary operator:

Loops

There are as many ways of writing a loop in JSX as there are in JavaScript, but the most common technique is to use map.

Let’s build another component, a list of posts this time:

We’re iterating over this.data.posts, and then calling this.renderPost on each item. A few things to note:

  • We’re using the new fat arrow shorthand syntax to define an anonymous function. This is the same as writing function (post) { return ... }.
  • We’re passing a reference to this.renderPost to map, not executing renderPost.
  • We’re using the map’s index to set a key on each node to help React find its way through the DOM.

Composing Components

React makes it very easy to compose components, i.e. use them inside each other. Assuming a <Post/> component that takes in a title and text, we can rewrite the previous “list of posts” example as:

We can even define wrapper components:

You’ll then be able to call <PostWraper>...</PostWraper>, with this.props.children getting replaced by whatever is contained between the opening and closing tags.

Putting It Together

Now that we’re more familiar with React syntax, let’s try to understand the Task component from the official React tutorial:

Here’s a breakdown of each section of the code:

  • First, we declare our new component with Task = React.createClass.
  • We then use the propTypes object to specify the two props expected by the component: a task object, and a showPrivateButton boolean. Both are required.
  • Next, we define the toggleChecked, deleteThisTask, and togglePrivate event handlers, which each call a different Meteor method.
  • The render function is where the real work happens.
  • First, we define a taskClassName variable (using the new const keyword) that concatenates a CSS class together based on the current task’s props.
  • We then return a JSX string (i.e. a bunch of HTML with JavaScript interpolated).

Notice how all the data displayed by the components came from props, and not data or state. This is what’s known as a “dumb” component, meaning all it does is take data in and spit out some HTML, without any interactivity of its own.

React Resources

If you want to learn more, there are plenty of resources on React out there. Here are a few to get you started.

Conclusion

As you can see React isn’t that scary! Learning enough React to be productive in Meteor shouldn’t take that long, especially if you already have a good handle on JavaScript itself.