Giter Club home page Giter Club logo

react-ive-meteor's Introduction

React-ive Meteor



Building a realtime backend and clientside optimistic UI for React can be difficult. Meteor makes it easy to build an app with optimistic UI updating and realtime data streaming (view updates as DB records change).

TL;DR

This repo aims to be a sandbox that developers can learn how to create React apps with a Meteor backend. We'll have several branches with different ways to architect/use the app (such as a full flux spec).

Meteor with Flux or Relay type experiments can be a bit complicated so the master branch will be the most simple version that beginners can pickup and start running.

The Meteor Development Group is working on making a deeper and more seamless integration with Meteor and React. Checkout the progress Here. The master branch is using the preview release of this package.


#### Benefits of using React with Meteor
  • Automatic optimistic UI updates (latency compensation)
  • Universal JS shared on client and server (isomorphic)
  • Real time database updates (like Uber's realtime driver location)
  • Hot code reloads
  • Mini-Mongo client data store (easy clientside querying)
  • Build system for preprocessing Sass, Babel, etc...
  • Clean server-side code with fibers (soon with promise ES7 async/await)
  • Query based data subscriptions instead of REST (also API REST supported)
  • Easy microservice implementations via DDP
  • Modular, swap out any default components you wish

Cons of using Meteor

  • No live-query support for SQL (non-reactive SQL supported via GraphQL)
  • No client-side file import system yet (v 1.3 will change this)

Fallacies of Meteor

  • Not secure - This has been resolved for quite a while... try to modify someone else's post!
  • Not scalable - Many companies are using Meteor with large user bases
  • Only supports Mongo - With GraphQL any promise based driver will work
  • Meteor is only for realtime streams - works well with without realtime updates too!

These cons are on the core roadmap and will be resolved in the near future. However some of those could be blockers for your project.




Usage

  • curl https://install.meteor.com/ | sh more info
  • make dev or meter --settings '.config/devel/settings.json'

## Data

Fetching data with Meteor is quite different than a traditional REST system. Instead of making requests to single resource endpoints, you can subscribe to one or more publications of data. If this data in the database changes, you'll receive the new data in the client (instantly when using Mongo's Oplog). Using the MeteorMixin, this new data is synced with your subscription/state which re-renders your views.

This new data is sent into a store called Mini-Mongo. It acts like an in memory Mongo database which turns out to be a really convenient way to access store data. Since this is in memory, ops are very fast (basically a key/value lookup). If you were using the PostgreSQL database you would use SQL to query the Mini-PostgreSQL store instead.

If you prefer a flux architecture, you can use Tracker to watch for changes and then emit a changed event.

The whole data cycle looks like this:

  • grandparent component renders children components
  • children tell grandparent which data/fields they need
  • grandparent subscribes to data all at one time
  • server publishes data to client if authorized
  • client accepts data and inserts into Mini-Mongo client store
  • grandparent receives message that data they care about changed
  • grandparent triggers re-render (via Meteor mixin)
  • data flows from grandparent down to all children

New Meteor users can get tripped up in this process by sending too much data to the client, causing slowdown. This project uses a GraphQL/Relay inspired subscription to help prevent over publishing data. Each component specify what fields they need and their grandparent takes care of the actual query. This grandparent pushes down new data through their props. This makes testing very easy as the fetching only happens in one place. This data fetching system is a first draft so it may change some.

Views

The master branch of this repo (and live example) use a mixture of Meteor's Blaze (handlebars like syntax) templates and React templates. Blaze is ideal for content that has no state and very little helpers. These large pages (like the about example) would be cumbersome to use in JSX.

In this setup, the router renders 'page' templates which have the sole responsibility of handling static markup and rendering the topmost React components. These Blaze pages don't subscribe to data, that responsibility is for the topmost components. Example Code

The rendering path looks something like this:

  • route /feed , routes.js render static client/pages/feed.html template
  • static feed template renders FeedList and CreatePost React components
  • FeedList sets up data pub/sub and renders children
  • CreatePost renders children
  • view is ready

However if your app looks very 'app like' (Spotify, Slack, etc...) and not 'page like', using 100% React views is a better approach. See the full-react branch (soon) to see how you can render React views in using the React-Router module.


## Meteor Methods

Meteor provides an RPC style method that can be called on the client or on the server (even other non servers with a DDP adapter). You simply write a method on the server and on the client you call Meteor.call('multiply', 2, 5);. On the server the call would directly return 10 because we have fibers. On the client we can't block so the last argument would be a callback with params error and response. You also have access to a few resources inside the method like this.userId. It will contain the caller's userId if they are authenticated. Meteor uses these methods under the hood for the Authors.insert({name: 'foo'}) calls. However we're using our own model methods to bypass the hard to reason allow/deny rules. The Meteor methods turn out to be pretty good at standing in for a Flux Dispatcher.


## Models

The implementation of data models used in this project is just one of many ways to do it. Meteor does not have an ORM or Model layer so you're up to rolling your own or using a package. There are a few nice model packages but they have lots of magic involved. For simplicity i'm using a pattern i've used in several production apps. However to keep code a bit smaller, the inheritance uses __proto__ which is not supported in old IE. You would need a more verbose method to make this work with unsupported (old) browsers. These models also are not full featured like Mongoose or ActiveRecord, but again for simplicity sake these will work just fine.


## Load Order

Meteor doesn't currently have a file based module import system like Browserfy, Webpack, or ES6 modules (though we can import them and expose globally like this example). However i've heard this is coming in the near future. Currently Meteor has a set of rules it uses for loading. Read the full rundown here. client/ folders are only sent to the client and server folders are only sent to the server. The both folder will be sent to both client and server.


## Code Generator

No one likes typing boilerplate. If this project's folder structure works for you, Meteor Generate can save a lot of time. I'm in the middle of converting my old MVC patterns with Blaze over to Component structured React. This should be on NPM soon but in the mean time keep an eye out on this branch. It creates models, pages, routes, React components with Sass styles, and more.


## Security

In short, trust nothing on the client. Assume everything being passed from the client to server could be a malicious value. Meteor provides utilities to check all inputs to make sure they are the shape and type you expect. This prevents Mongo injections. If they're not the shape/type you expect, reject it and throw an error. remove the insecure package. It automatically allows full access to insert/update/remove methods. This would be great for a throw away prototype or for learning the very basics but it's a security hazard.

The autopublish package should also be removed. This will send your entire serverside database to the client and load it into the Mini-Mongo store. Not only is this slow with large data sets but it's a security hazard.
Only send authorized data to the client. It's up to you to verify if a user should be allowed to subscribe to a publication. They can't access it in Mini-Mongo unless you send it to them. You only want to send data down that they are allowed/supposed to use.

Meteor Security Talk See Code Comments

react-ive-meteor's People

Contributors

adambrodzinski avatar chenkaic4 avatar rozzzly avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-ive-meteor's Issues

Redux Style

I notice this is very similiar to a redux style. I notice the domains, but would moving that to reducers be possible?

Need better looking dates

It should really use something like the Moment JS lib to say '3 hours ago' or even a properly formatted date.

Installation Error

users-MacBook-Pro:reactive user$ make dev
meteor \
        --port 3000 \
      --settings '.config/devel/settings.json'
[[[[[ ~/reactive ]]]]]

=> Started proxy.

=> Meteor 1.1.0.3: fixes Facebook integration for new apps.


This release is being downloaded in the background. Update your app to
Meteor 1.1.0.3 by running 'meteor update'.

=> Started MongoDB.
=> Errors prevented startup:

   While loading plugin `compileScss` from package `fourseven:scss`:
   module.js:356:32:
   dlopen(/Users/user/.meteor/packages/fourseven_scss/.3.1.1.vg4ybo++os.osx.x86_64+web.browser+web.cordova/plugin.compileScss.os.osx.x86_64/npm/compileScss/node_modules/node-sass/vendor/darwin-x64-11/binding.node,
   1): Symbol not found: __ZNSt12out_of_rangeD1Ev
   Referenced from:
   /Users/user/.meteor/packages/fourseven_scss/.3.1.1.vg4ybo++os.osx.x86_64+web.browser+web.cordova/plugin.compileScss.os.osx.x86_64/npm/compileScss/node_modules/node-sass/vendor/darwin-x64-11/binding.node
   Expected in: /usr/lib/libstdc++.6.dylib
   in
   /Users/user/.meteor/packages/fourseven_scss/.3.1.1.vg4ybo++os.osx.x86_64+web.browser+web.cordova/plugin.compileScss.os.osx.x86_64/npm/compileScss/node_modules/node-sass/vendor/darwin-x64-11/binding.node
   at Module.load (module.js:356:32)
   at Function.Module._load (module.js:312:12)
   at Module.require (module.js:364:17)
   at require (module.js:380:17)
   at Object.<anonymous>
   (/Users/user/.meteor/packages/fourseven_scss/.3.1.1.vg4ybo++os.osx.x86_64+web.browser+web.cordova/plugin.compileScss.os.osx.x86_64/npm/compileScss/node_modules/node-sass/lib/index.js:16:15)
   at Module._compile (module.js:456:26)
   at Object.Module._extensions..js (module.js:474:10)
   at Module.load (module.js:356:32)
   at Function.Module._load (module.js:312:12)
   at Module.require (module.js:364:17)
   at require (module.js:380:17)
   at Object._.extend.Npm.require
   (/Users/user/.meteor/packages/meteor-tool/.1.1.3.dzw9kd++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/tools/bundler.js:1341:22)
   at Package (packages/compileScss/plugin/compile-scss.js:2:1)
   at <runJavaScript-30>:146:4
   at <runJavaScript-30>:153:3


=> Your application has errors. Waiting for file change.

Install error with scss

When doing a fresh install with, git clone https://github.com/AdamBrodzinski/react-ive-meteor. I got the following error:

[rozzzly@digitalsea react-ive-meteor]$ meteor
[[[[[ /var/www/react-ive-meteor ]]]]]

=> Started proxy.
=> Started MongoDB.
=> Errors prevented startup:

   While building the application:
   /var/www/react-ive-meteor/client/styles/_components.scss:4:9: Scss compiler error: file to import not found or unreadable: ../components/paramsExample/paramsExample
   Current dir: /var/www/react-ive-meteor/client/styles/


=> Your application has errors. Waiting for file change.

It looks like the scss compiler is unable to load that file. After inspection, it appears that the issue is with a difference in the casing in the file name. I have resolved the issue and will submit a pull request shortly.

comments of feeds got by "load more" don't display

(sorry, my English is poor, specially in writing and listening. I hope I can give a clear description)

When I click "load more" bottom, five new Feeds will be loaded successfully. But the comments of these new Feeds disappear.

I found that when sub completed, the postIds represent all current Feeds, but, we just can invoke it in next click of 'load more' or something else which will trigger reactive of pub/sub(e.x. click 'like' bottom) or change the state of Component(e.x. click 'load more' bottom).

we can go to http://react-ive.meteor.com/feed to see this bug.

the code with this bug:

startMeteorSubscriptions() {
    var fields = this.state.fieldsNeeded;
    var postIds = this.data.postIds;
    var recordCount = this.state.recordCount;
    return Meteor.subscribe("feed", fields, recordCount, postIds);
  },

  getMeteorData: function() {
    var sub = this.startMeteorSubscriptions();

    return {
      feedReady: sub.ready(),
      postItems: FeedDomain.getAllFeedPosts(),
      // ok, postIds are all here, but current sub can't use it any more, because sub is completed.
      postIds: FeedDomain.getPostCommentIds()
    };
  },

I have tried to fix this bug to get this demo better. The problem is that: very time "load more" bottom be clicked, the postIds passed to sub is collected among Feeds got in last sub. so the pub don't send the new Feeds's comments. So just let pub know the new Feeds, and update postIds.

  // current 'load more' postIds, 
  var loadMoreStep = 5;
  var newPostIds = Posts.find({}, {
                                  fields: {'_id': 1},
                                  sort: {createdAt: -1},
                                  limit: limits.posts,
                                  // just got new Feeds
                                  skip: limits.posts - loadMoreStep}
      ).map(function (post) {
        return post._id;
      });
  // update postIds
  postIds = _.union(postIds ? postIds : [], newPostIds);

  // returns Mongo Cursors
  return [
    Posts.find({}, {fields: fields.posts, sort: {createdAt: -1}, limit: limits.posts}),
    // postIds determines the comments sended to mini-mongo
    Comments.find({postId: {$in: postIds}}, {fields: fields.postComments})
  ];

I have create a PR #11, wish for review.

incrementLimit

Hi, what do you think about the incrementation limits and how to pass them to subscriptions?
Actually we could just use the Sessions from meteor by Incrementing it on the one side and get the Session again from the other side for the subscription. In this case we don't even need the getInitialState() method. But this seams not the favored way to be.. If we shouldn't use it, how should we do it instead?

Question on Component Instantiation

Hey!

Great start project. I'm starting a second Meteor project and looking to use React for the views, and came across your repo. It seems like a perfect starting point, I just had one question - why do you deviate from the standard component instantiation described in the Meteor React Preview docs http://react-in-meteor.readthedocs.org/en/latest/meteor-data/:

var TodoListLoader = React.createClass({
  mixins: [ReactMeteorData],
  getMeteorData() {
(...)
  }
});

Instead, you use:

class FeedList extends React.Component {
  // TODO break out more button into comp
  render() {
    console.log("[FeedList] Rendering");
(..)
  }
}

I rewrote your code the first way and it seems to work fine....

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.