React for Meteor Developers
NOTE: This post was originally published on the Differential Blog.
What is React?
Does React Replace Meteor?
Nope! Since React is only a “user interface library” it only replaces the “views” of your Meteor apps — that part that Meteor calls Blaze. So rather than writing your interface using Blaze templates, helpers and events handlers, you write them using React components. You can still leverage all of the great time-saving, productivity-boosting features of Meteor like automatic file loading, a simple unified package manager, realtime updates out-of-the-box, etc, etc.
Advantages over Blaze
So if Meteor already has Blaze, why would you want to use React?
React was developed out of the real-world experiences of the engineers at two of the world’s largest consumer web applications: Facebook and Instagram. If it works for those guys there’s a good chance it will work for your team too!
Anyone who has used Meteor for any amount of time has probably found themselves struggling to wrangle multiple “reactive” data sources. Meteor’s realtime nature can be both a blessing and a curse. React attempts to ease this complexity by intelligently “refreshing” your entire component everytime its data changes. For those of us coming from a server side background, this can feel like the “good old days” of developing simple request/response interactions.
React encourages you to write small, reusable components with a single focus. For larger projects this can be a godsend compared to the monolothic Blaze templates and “jQuery soup” that you often see in big Meteor apps.
React is about more than just writing code that _works_, it’s also about writing code that _works for your team_. React allows you to write code that your teammates can comprehend quickly and modify confidently.
While watching a React talk titled “React: RESTful UI Rendering" (which I highly recommend, especially if you are coming from a Rails background as I am) I was introduced to the term The Pit of Success.
The Pit of Success: in stark contrast to a summit, a peak, or a journey across a desert to find victory through many trials and surprises, we want our customers to simply fall into winning practices by using our platform and frameworks. To the extent that we make it easy to get into trouble we fail. — Rico Mariani, MS Research MindSwap Oct 2003.
React can be very frustrating at first because it literally forces you to do things the “right” way. However, anytime I hit a wall with React I later realized it was because I was trying to do something that would have gotten me in trouble later. If you find yourself initially getting frustrated with React I encourage you to stick with it a while longer and try to embrace “The React Way” of doing things.
React Lessons Learned
The official React docs do a great job explaining the key concepts of React and are a great place to start if you’re looking to learn the basics. In this section I’ll focus on two key best practices we’ve learned while building our first React app.
1. Keep your children dumb
The key to keeping your React components small and focused is to nest them in a parent/child hierarchy. React calls this composability. I’ve found that there are two primary concepts you need to know to do this the “React Way”:
Parents talk down to children, because children are dumb
You can probably tell I’m not a parent ;) — but the key take away here is that parent components are responsible for any computations or data fetching and then passing the raw data to child components. Child components should be as simple (or “dumb”) as possible, just dutifully rendering the data that they are passed.
Parents tell children what to do, not the other way around
Children components often need to trigger events or modify state. Think of a `<DeleteButton />` component nested inside of a `<PostItem />` component which is nested in a `<PostList />`. In this case it’s the `<PostList />`’s responsibility to tell the `<DeleteButton />` what to do when clicked. This is done by passing callbacks all the way down the hierarchy:
2. Keep your JSX clean
Using React with Meteor
Ok, so you’re ready to give this React thing a try? Lucky for you Meteor makes this super easy. In fact, they’ve made it so easy that they’ve already written a great tutorial for it so that I don’t have to! Instead I’ll focus on a few of the key lessons we’ve learned while integrating React and Meteor:
Any Meteor data sources you want to access in your components should happen in `getMeteorData` — not `getInitialState` or `componentWillMount`. This includes the obvious things like data from your collections — but also the subscriptions to those collections as well as all other reactive data sources like `Session`, `Meteor.user`, `ReactiveVar`, etc.
Speaking of fetching data, there’s a common React pattern called “Container Components” that we’ve found particularly useful. The general idea is to separate your data-fetching and rendering concerns by wrapping your components in “containers” whose sole responsibility is to fetch the data needed by its children. This fits right in with React’s concept of composability mentioned above. There’s a great overview of Container Components on Medium if you’d like to dig in deeper.
Embrace the Ecosystem
One of the 7 Principles of Meteor is “Embrace the Ecosystem”. When building UIs with React I’ve found that leveraging existing React components is hugely helpful. React Router, React Bootstrap and Material UI are just a few of the packages we’ve leveraged from the React community to boost our productivity.
What the Flux?
If you’ve read anything about React, you’ve probably come across something called Flux. So what is Flux?
The Glue Between Components
If you remember above I mentioned that React components only communicate hierarchically — between parents and their children. So what if you want two sibling components to communicate? Or several components that are all in totally different areas of your app? This is where Flux comes in. You can think of Flux as a repository of shared application state (which Flux calls “Stores”) and a global event bus (which Flux calls the “Dispatcher”). Components that want to share state would subscribe to a Store (or mutliple Stores), and send events to the Dispatcher (the global event bus) to modify the state in the Store(s). When a Store is modified, all of its listener components re-render appropriately.
Flux + Meteor
So does Meteor need Flux? Meteor’s collections and server-side methods can replace a lot of what you would use Flux for. If your components “subscribe” to a Meteor collection in `getMeteorData` they will re-render appropriately whenever that collection is modififed. In my experience I haven’t felt the need to implement a Flux library. However there has been quite a bit of discussion about Meteor and Flux on the official Meteor forums, as well as some great examples on Github, so I urge you to check those out and form your own opinion.
But Meteor Already Supports Cordova!
In his keynote Tom made the bold statement that “Write Once, Run Everywhere” is a “pipe dream” and that the goal instead should be to “Learn Once, Write Anywhere”. This directly contradicts Meteor’s motivation for including Cordova support. So who’s right? Well as always, it depends. It’s hard to beat the look and feel of a truly native app and React Native takes a lot of the pain out of building them, so if you have the resources it’s a great option. But for teams on a tight budget or timeline, or whose audience may be less sensitive to the differences between native and hybrid apps, Cordova is still a valid option.
React Native + Meteor
At Differential we’re currently right smack in the middle of our first React Native + Meteor project, so look for a future blog post from our own Spencer Carli detailing the highs and lows of integrating React Native and Meteor. And feel free to nag him on Twitter in the meantime ;)
UPDATE: Thanks to Spencer for publishing his post finally :)
Should you use React in your next Meteor project?
But as your application — and more importantly your team — grows, you may find yourself feeling the pain of unpredictable application state, duplicated code and “jQuery Soup”. In that case I’ve found that React is a great choice for building predictable, scalable apps and feels right at home in a Meteor app.