Log In

Getting started with Meteor


by Yariv Katz

This article is a starting point to learning Meteor. We will learn what is meteor and how to start using it.

What is Meteor

Meteor is a fullstack framework for rapid creation of a frontend + backend + database project. For the frontend we can use any of the popular ui libraries or frameworks. The backend is built on nodejs. The idea is pretty simple, some code will belong only to the client, some code will belong only to the server, some code will belong to both. The code that is shared between the client and server will hold the models that will be connected to the database, this means the the server will have access through the models to the mongo collections and also the client will have a mini mongo, database cache and will be able to access the database as well by using the same model. Another nice Meteor feature is the support for mobile apps, with a few commands we can turn our app to a mobile app using cordova.

What we want to create

In this tutorial we will combine meteor and react to create a todo application. Our database will contain a collection to hold the todo tasks. Our client will perform CRUD operations on the collection.

Bootstrap meteor and react

Let's start a new meteor project with the client set to react. Install Meteor by typing in the terminal:

> curl https://install.meteor.com/ | sh

If the installation is successful you will be able to type the meteor command in your terminal, check the meteor version by typing:

> meteor --version

Now we need to start a new meteor project with react as client, in the terminal type:

> meteor create --react meteor-todo

This command will bootstrap a new meteor project. To run your project in the terminal:

> cd meteor-todo
> meteor

When starting a new project, meteor also installs mongo and when we run our project, a mongo database server is run as well. Our project is already connected to a mongo database.

Going over the files

When we bootstrapped a new project we see the following project structure:

  • client - The client folder holds file that will be loaded on the frontend only
  • imports - The imports folder holds code that will run on both the client and server. Meteor also created a starter project displaying a counter and links loaded from the database. the api folder in here holds the models that are connected to the database. The ui folder hold the react application.
  • server - These file will only run and be exposed by our server.
  • tests - holds our unit testing

Database model

We want to create a Tasks collection in our mongo database. That collection should be synced with our client. In imports/api/tasks.js place the following code:

import { Mongo } from 'meteor/mongo';

export const Tasks = new Mongo.Collection('tasks');

Now we want to connect the data from the database to our client

Connecting Meteor data to React components

Now we want to pass the tasks from the db collection to our App component. To pass meteor data to our component we need to use a meteor package called: react-meteor-data. In the terminal type:

> meteor add react-meteor-data

This will expose a Higher-Order-Component called withTracker. We can use this to wrap our components with published data from the server. There are several ways to deal with data passed from the server in the client, the common one will be with the publish subscribe. Our server will publish any changes to the data (usually from the database) and the client will subscribe to those changes. The HOC withTracker will subscribe to data from the server and will render our component when the data is changed, while passing the data to our component props. To pass the tasks to the App.jsx root component, we will wrap that component with the withTracker while subscribing to Tasks.find(). Change the code in imports/ui/App.jsx to this.

import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import PropTypes from 'prop-types';
import { Tasks } from '../api/tasks';

const App = ({tasks}) => (
  <div>
    <ul>
        {
            tasks.map((singleTask) => <li key={singleTask._id._str}>{singleTask.title}</li>)
        }
    </ul>
  </div>
);

App.propTypes = {
    tasks: PropTypes.array
}

App.defaultProps = {
    tasks: []
}

export default withTracker(() => {
    return {
        tasks: Tasks.find({}).fetch()
    }
})(App);

We are using the withTracker to pass the tasks from the db to our component, when the data is changed our component will rerender. In our App.jsx we will now add a form to add tasks to the collection. Modify the App.jsx to this:

import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import PropTypes from 'prop-types';
import { Tasks } from '../api/tasks';

const App = ({tasks}) => {
    const titleRef = React.createRef();
    const addTask = (event) => {
        Tasks.insert({title: titleRef.current.value});
        event.preventDefault();
    }
    return (
        <div>
            <ul>
                {
                    tasks.map((singleTask) => <li key={singleTask._id._str}>{singleTask.title}</li>)
                }
            </ul>
            <form onSubmit={addTask}>
                <input type="text" ref={titleRef} />
            </form>
        </div>
    );
}

App.propTypes = {
    tasks: PropTypes.array
}

App.defaultProps = {
    tasks: []
}

export default withTracker(() => {
    return {
        tasks: Tasks.find({}).fetch()
    }
})(App);

Try and launch your app and notice that every time you add an item the list is refreshed. Try and do the same with another client openning the app, even if another browser is adding an item the lists of both of them are refreshed.

Meteor Downside

Meteor works perfect on small data with small amount of users, but performance wise it didn't scale as expected when the data was really big with a lot of users accessing it. Consider that meteor has to keep the data sync with many users and it will cause a lot of memory and cpu usage in our server as well as in our client (which holds the collection in mini mongo in memory). I would not recommend using meteor if your collection and users will grow. Although there is a way you can share data and take care of syncing yourself so you can avoid the sync in large collections but then you are kind of using the meteor benefits. Another downside to consider is the tight coupling between db, server, and client.