Meteor 1.3 – Creating React Components

It’s a crazy time to be a Meteor developer, 1.3.x represents the biggest change yet and points us in a more sustainable direction that fits with a wider JavaScript/Node ecosystem and React has just rolled out version 15 which IMHO is simply amazing! that said if your not 100% up to speed with the direction of travel its a pretty confusing space to be in. For example, creating a simple react component in your Meteor application can be done in a myriad of different ways and depending on the tutorial your following our the guide your reading you will find yourself sleep walking into a convention that may or may not be the best practice.

In this article i’m going to discuss the ways you might have seen React components defined and even the ways in which you might be depending on React in order to tease out the knowledge that will allow you to make the most informed choice, I might also share an opinion or two 😉

React Dependency

in Meteor 1.2 you would have been comfortable with dependencies as it was all about Packages, to make use of React you would simply meteor add react and boom! your now a react developer. This simplicity is what made you fall in love with Meteor (it was for me anyway) now you could be sure that react was available globally in your app.

Moving forward to Meteor 1.3 you can still do this, but the guidance says otherwise… The headline feature of 1.3 is ES2015 module support which gives us NPM integration client and server side out of the box, this means we don’t rely on package maintainers to give us the latest versions of NPM modules (like React) we can simply npm i react -S and we now have access to the latest version of React (15.0.0 at the time of writing this) however this doesn’t make it globally available like the package did, you have to be explicit when you use it.

The following code snippet illustrates a very simple React component that adheres to the new import/export syntax.

You see on line one we are explicitly importing React in to the current context, without that line the Meteor build system would fail. You will also notice the last line we are “exporting” our HelloWorld component which in turn means to use it we should import it where we need it (makes sense right?).

React from Meteor Package or NPM?

On the face of it you might say that the package is easier and while it arguably is (less code at least) you really should be using the NPM module rather than the package in Meteor 1.3, If you are building a React application you will inevitably need to use other NPM modules and having React included from the Package can cause all sorts of issues where React gets loaded twice (different version too!), plus MDG are never going to keep up with Facebook so the React package is always going to be ever so slightly behind the NPM module (for example v15.0.0 isn’t available as a package yet).

So remove that old React package if you have it and install it from NPM.

React Components

Now that we have the NPM version of React we are good to go, but this is where things get “interesting”… If you were to read the first 10 articles on Meteor and React you would find at least 3 very different ways of defining React components and another 3-4 different ways of managing state (Transient state, Collections, etc…). This is where React appears complex but it really isn’t we just need to understand the approaches and pick the one that i say is best pick the one that is most appropriate to our use case.

I’m primarily going to discuss defining React components in this articles, managing “Data” (or State) is something for another article (yep, its in the post). The three (at least) ways you will have seen React components will as follows:

1 The legacy createClass method

2 The Modern (es6) Class based method

3 The stateless function Method

The first two variants (1 React.createClass and 2 extends React.Component) are essentially doing the same thing albeit using different features of the JavaScript language to do it, but what you end up with is essentially the same with a few gotchas:

You can’t use Mixins with the option 2 – at least not in the way the meteor tutorials will have shown you.

setProps is deprecated in option 2

getInitialState doesn’t exist in option 2 instead you just define a constructor and set any default state there (make sense)

The second option looks (based on the evidence I have given) as the poorer version of the two however it really is not only because we want to be using ES6 rather than ES5 and because React has taken an opinionated approach to building components understanding option 3 (Stateless Functions) will help you see why.

Stateless Components

Our example HelloWorld component is the simplest component you will ever see, its stateless by definition however for the purpose of this I’m going to introduce HelloWorld2.jsx which is a slightly more complex version of the HelloWorld component we used earlier:

This version is still stateless but it required data to be passed in to it via props (e.g. <HelloWorld2 title=”Hello World” />), now imagine that the data you pass into this component isn’t “Hello World” and its in fact from a Database (or some state someplace), perhaps its the current users name…in this case the component is still fine to use as-is because you would simply pass the value of the users name in via props (e.g. <HelloWorld2 title={username} />) but how you get that data and how you manage it is a new problem all together, at some point a parent component of the HelloWorld2 component is going to need to use state to deal with this data, React will do the hard work and update child components (that need to be updated) when state changes but the component that deals with this state is by definition “State-full” thus will be defined using the other conventions (1 or 2).

(TL;DR) So what should I do?

You should be using ES6 syntax when building React components unless you have a (REALLY) compelling reason not too, so the legacy React.createClass syntax and [Mixins] should not be used (i’m sure this will be deprecated soon too). Building your components as stateless functions that make use of props (for data and functions) makes you think about when and where you need to get data in to your application. Anyone who has been using React for more than a day will tell you that thinking about the hierarchy of your components in relation to the hierarchy of your applications state (Data) is half the battle, thinking in this manner means you will produce much more maintainable React applications.

But doesn’t Meteor need the MeteorData mixin to work reactively with React?

No! no it doesn’t and as i said you shouldn’t be using Mixins any more, managing Data is another article all together but i will leave you with my opinion. Lets say we want to use our HelloWorld2 component but we want the title to be the users name… We already have a stateless functional component that does this we just need a container component that deals with state and to handle the Meteor specific (namely reactivity) we can use react-komposer.

The following example illustrates us using react-komposer to build a container for our HelloWorld2 component that deals with getting the users name and passing it in to the component as props.

Here we see that we have our HelloWorld2 component as before but we also have a HelloWorld2Contianer which uses react-komposer, the compose method is reactive so any reactive updates inside of it will update the state (the object that is passed to onData) so React will update whenever the users changes (or becomes a value). In app.jsx we simply use HelloWorld2Container instead of the HelloWorld2 component and we have a Reactive state-full container around our Stateless functional component.

This may seem like overkill (and in our contrived use case it might well be) but you now have a component that works with Meteor but doesn’t rely on Meteor, you could share this stateless component with a team using different technology all together, they just need to figure out how to get data to is (using the conventions appropriate to them and there stack). Having container components also makes it super east to refactor your code base, as i mentioned earlier understanding the hierarchy of your apps state if key to a React project but you wont get it right first time so moving the responsibility of fetching data and managing state will be a constant theme during your development, having stateless functional components will make that refactoring a breeze.