Skip to content
(DEPRECATED) Meteor package that contains essential mixins for using React with Meteor
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
examples/leaderboard
src
.versions
CHANGELOG.md
LICENSE.txt
README.md
package.js

README.md

#DEPRECATED This package has been deprecated in favor of the official Meteor React package, react-meteor-data.

Meteor & React

This a Meteor package that includes 2 React mixins that enable binding reactive data sources and DDP subscriptions to a React Component.

If you're looking for a JSX compiler see grigio:babel

Table of Contents

  1. Usage 2. ReactiveMixin 3. DDPMixin
  2. Loading React
  3. How it works
  4. Future Fork

Usage

Installation

meteor add grove:react

ReactiveMixin

This mixin provides a way of binding reactive data sources to a React component. Components that use this mixin should implement a method named getReactiveState and return an object from that method, much like the standard getInitialState. Within the getReactiveState function you must make sure to call on reactive data sources or else the method won't rerun.

Example

Bookface = React.createClass({
  mixins: [ ReactiveMixin ],
  
  getReactiveState: function() {
    return {
      friends: Friends.find().fetch(),
      loggedIn: !!Meteor.user()
    }
  },
  
  render: function() {
    if (this.state.loggedIn) {
	    if (this.state.friends.length > 0) {
	      return <h1>You've got friends!</h1>
	    }
	    return <h1>Forever alone...</h1>;
	 }
	 return <h1>Please log in</h1>
  }  
});

DDPMixin

This mixin provides a way of binding DDP subscriptions to a React component. Components that use this mixin should implement a method named subscriptions and return either a single subscription handle or an array of subscription handles. You can then call subsReady() within getReactiveState to reactively wait on them, or check this.state.subsReady from within the render function to see if they're ready. (You can also call this.subsReady() from within render but it follows React convention more closely to use the component's state).

Make sure to include the DDPMixin before ReactiveMixin for the component. As stated in the Reusable Component docs, "methods defined on mixins run in the order mixins were listed, followed by... the component." DDPMixin must run first and define the subsReady function before it can be called within getReactiveState.

An interesting use case might be to have a component that makes its own DDP connection and uses that instead of the default Meteor connection. Meteor.subscribe is just a bound wrapper around a DDP connection

A SubsManager object from meteorhacks:subs-manager could also be used instead of Meteor.subscribe.

Example

Post = React.createClass({
  mixins: [ DDPMixin, ReactiveMixin ],

  getInitialState: function () {
    return {
      post: null
    };
  },

  getReactiveState: function() {
    if ( this.subsReady() ) {
      var p = Posts.findOne( Session.get('currentPostId') );
      return { post: p };
    }
  },

  subscriptions: function() {
    return Meteor.subscribe('singlePost', Session.get('currentPost') );
  },
  
  // or if you want to wait on multiple subscriptions
  subscriptions: function() {
    return [
		Meteor.subscribe('singlePost', Session.get('currentPostId') ),
		Meteor.subscribe('postComments', Session.get('currentPostId') )
    ];
  },

  render: function() {
    if ( this.state.post ) { // or this.state.subsReady, but if the publication
      return (			     // was empty then this.state.post is undefined
        <main id="Post">
			<p>{this.state.post}</p>
        </main>
      );
    }
    return <h1>Loading...</h1>;
  }
});

For more modularity you could use the params from your Router instead of Session.get

Loading React

It's recommended to use cosmos:browserify to get the React library itself. To do so correctly, you'll want to create a local package, require what you want, and then explicitly export them. You want to use a local package so that it gets loaded in before your application. For example, if you want to use React with addons and React Router:

// packages/client-deps/package.js
Package.describe({
  name: 'client-deps',
});

Npm.depends({
  "react" : "0.13.3",
  "react-router" : "0.13.3"
});

Package.onUse(function(api) {
  api.use(['cosmos:browserify@0.2.0']);
  api.addFiles(['browserify.js']);
  api.export(['React', 'ReactRouter']);
});
// packages/client-deps/browserify.js
React = require('react/addons');
ReactRouter = require('react-router');

React and ReactRouter will then be exposed at the global scope to both the client and server.

A note on using the production version of React: The difference between the development and production versions of React is more than just minification. There are warnings that are removed and optimizations made. To remove these warnings, make sure that your NODE_ENV environment variable is set to "production" when building your app. The envify transform present in cosmos:browserify will replace process.env.NODE_ENV with "production" throughout the library, and then when Meteor runs UglifyJS it'll eliminate the now-dead code.

How it works

Reactive Subscriptions

All of the subscription handles that are returned from subscriptions have .ready() called on them, which is a reactive data source. Every time a new subscription becomes ready it will check them all again. Once they are all ready, a ReactiveVar is set to true. The component method this.subsReady() is actually a bound get call on a ReactiveVar.

var subsReady = new ReactiveVar(false);
this.subsReady = subsReady.get.bind(subsReady);

When called from within getReactiveState, it sets up a dependency on that method's Tracker.autorun even as a bound function (which is pretty awesome).

Future Work

Server-side

The package loads React onto server and client, but the mixins are not supported on the server since Tracker and Meteor.subscribe are not supported on the server. Thoughts and pull requests welcome.

You can’t perform that action at this time.