Offline Synced Database With Meteor, React Native and Realm

Miguel Morujão
3 min readAug 10, 2017

--

Tech Stack

If you want to create an app that works offline but you don’t want to release a new version every time you want to update data, this seems like a great solution, it also works on both Android and IOS.

The main concept is that you have a meteor server running with a backoffice app. The user has the app running in his phone and every time he is using the app while connected to the internet the app will establish a ddp connection with the meteor server and will check if there are any differences between the server data and the local data, if there are then the client will update the local database.

Prerequisites

  • A meteor app
  • A react native client

Ready? Lets get started!

First lets connect our react native client to our meteor server using the react-native-meteor package. Read the compatibility notes, to see what version matches your react native version. This part of the tutorial is based on this article, check it out!

npm install --save react-native-meteor // or yarn add react-native-meteor

In your react native app you should have a common index.js (entry point) for both platforms and above that you should also have an index.ios.js and an index.android.js. Anyway this is out of this article’s scope. But you should do something like this to get our cross platform code working.

// index.ios.js, index.android.js

import { AppRegistry } from 'react-native';
import App from './app/index';

AppRegistry.registerComponent('Demo', () => App);

In our index.js we should establish the ddp connection with the meteor server.

// app/index.js
import React, { Component } from 'react';
import {NetInfo} from 'react-native';
import { StyleSheet, Text, View} from 'react-native';
import Meteor from 'react-native-meteor';
//replace for your ip
const SERVER_URL = 'ws://192.XXX.X.XXX:3000/websocket';
class App extends Component {
//Establish connection with server on component mount
componentWillMount() {
const connected = () => {
Meteor.connect(SERVER_URL);
};
//Intial connection check
NetInfo.isConnected.fetch().then(isConnected => {
if (isConnected) {
connected();
}
});
//Check connection change
const handleFirstConnectivityChange = (isConnected) => {
if (isConnected) {
connected();
}
NetInfo.isConnected.removeEventListener('change', handleFirstConnectivityChange);
};
NetInfo.isConnected.addEventListener('change', handleFirstConnectivityChange);
}
// Removed the rest of the code for brevity
};
export default App;

This also looks for network changes and tries to connect to the server when you are connected to the internet. DDP connection is done, now lets leave this for a moment.

Now lets setup realm on our react native client app.

Hopefully you will just need to install the package and link it

npm install --save realm  //or yarn add realm 
react-native link realm

If you have any problems setting up realm please check this page.

Finally we can work on syncing our realm database with the server.

Remember our connected functon on index.js in our react native app? The one that fired whenever the device connected was connected to the internet? Good, now we must add some code to that function in order to retrieve data from the server, then compares it with local data and if it detectes any changes, rewrites the local data.

But before you must require realm on index.js.
And also a Schema relative to the entity you want to create, in this example is the entity Contact that has a name and the contact itself.

//index.jsconst Realm = require('realm');const ContactSchema = {
name: 'Contact',
properties: {
name: 'string',
contact: 'string'
}
};

Then you can add the code to sync the server data to the local database. You should have a ‘get.contacts’ method on a server that returns an array of contacts ex : [{name: “A”, contact: “999”},{name: “B”, contact: “888”}]

//index.jsconst connected = () => {
Meteor.connect(SERVER_URL);
Meteor.call('get.contacts', (err, res) => {
if (res) {
Realm.open({schema: [ContactSchema]}).then(realm => {
const contacts = realm.objects('Contact'); // retrieves all Contacts from the Realm
//Check if server has more contacts than local database
if (res.length > contacts.length) {
realm.write(() => {
//delete all before inserting
realm.delete(contacts);
res.forEach((contact) => {
try {
realm.create('Contact', {
name: contact.name,
contact: contact.contact
});
} catch (e) {
console.log('Error on creation');
}
});
});
}
});
}
});
};

Whenever you need to retrieve contacts you should access your synced local database.
And this should do it, try it yourself and feel free to ask any questions that you might have.

--

--