React Native and Couchbase Lite

How to integrate react native with couchbase lite

Jose Miguel
5 min readOct 14, 2016

Introduction

Couchbase is one the most promising NoSQL database available in the market and at Famoco, we like it a lot. One of the things we have been playing around here is with Couchbase Sync Gateway and Couchbase Lite for our Android devices.

In this article, I will write a brief introduction on how to use Couchbase Lite for React Native. I developed an example for the Android platform using the movie sample database that comes with it.

The React Native package usage in this article is located under the couchbaselabs directory:

https://github.com/couchbaselabs/react-native-couchbase-lite

The source code of the app is at my github:

https://github.com/jmn8718/RNCouchbaseExample

Prerequisites

In order to have the app fully functional, we need an instance of Couchbase Server, Sync Gateway, and preload MoviesExample.json(link).

Running couchbase sync gateway

docker run -p 4984:4984 -d --name sync_gateway_rn couchbase/sync-gateway:1.3.1-community https://raw.githubusercontent.com/couchbase/sync_gateway/master/examples/basic-walrus-bucket.jsoncurl http://localhost:4984{“couchdb”:”Welcome”,”vendor”:{“name”:”Couchbase Sync Gateway”,”version”:1.3},”version”:”Couchbase Sync Gateway/1.3.1(16;f18e833)”}%

Feeding data

wget https://raw.githubusercontent.com/couchbaselabs/react-native-couchbase-lite/master/ReactNativeCouchbaseLiteExample/MoviesExample.jsoncurl -H 'Content-Type: application/json' -vX POST 'http://localhost:4984/db/_bulk_docs' -d @MoviesExample.json

Installation

The first step it is to create a new app using the react native cli

react-native init RNCouchbaseExample

When everything is ready, we need to install the Couchbase Lite package

npm install --save react-native-couchbase-lite

If you do not have rnpm installed in your system, run the following command

npm install -g rnpm

And then we link the package to our project running the command

rnpm link react-native-couchbase-lite

Once it is installed we need to modify some files in the android project.

In the file android/app/build.gradle, we need to add in the android section

packagingOptions {
exclude 'META-INF/ASL2.0'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}

The next step is to register the package in the MainApplication.java

First, we import the component

import me.fraserxu.rncouchbaselite.ReactCBLiteManager;

And then we add the package

@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ReactCBLiteManager() <----- Register the module
);
}

Develop

Now we are going to develop the react native app. For that, we are going to create a new folder called app where we are going to have our project files.

Inside this folder, we create a file index.js and we move the code from the index.android.js, the index.js with the following code:

import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});

And then index.android.js is going to be:

import {
AppRegistry,
} from 'react-native';
import App from './App';
AppRegistry.registerComponent(RNCouchbaseExample, () => App);

The next step is to add the Couchbase Lite package and add the constants with our Sync gateway server

import {
manager,
ReactCBLite,
} from 'react-native-couchbase-lite';
const SG_URL = '<ip_sg_server>:<port_sg_server>';
const DB_NAME = 'db';

We are going to render a react native ListView and add a dataSource to our state to store the movies.

In our constructor we create a dataSource and we add it to the component state

const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = { dataSource: ds.cloneWithRows([]) }

The next step is to add the database to our code, we are going to initialize it in the componentDidMount event

componentDidMount() {
ReactCBLite.init(url => {
const database = new manager(url, DB_NAME);
database.createDatabase()
.then(res => {
database.createDesignDocument('main', {
filters: {
year: 'function (doc) { if (doc.year === 2004) { return true;} return false;}'
},
views: {
movies: {
map: 'function (doc) { if (doc.year) { emit(doc._id, null);}}'
}
}
});
const REPLICATION_OPTIONS = {
continuous: true,
};
database.replicate(`http://${SG_URL}/${DB_NAME}`, DB_NAME, REPLICATION_OPTIONS);
database.getInfo()
.then(res => {
database.listen({
since: res.update_seq - 1,
feed: 'longpoll',
});
database.changesEventEmitter.on('changes', function (e) {
this.setState({sequence: e.last_seq});
}.bind(this));
})
.catch(e => console.log('ERROR INFO', e))
})
.then(() => database.queryView('main', 'movies', {include_docs: true}))
.then(res => this.setState({
dataSource: this.state.dataSource.cloneWithRows(res.rows),
}))
.catch(e => console.log('ERROR', e));
})
}

Let’s go over the code, first we instantiate a new manager with the name of the local database, and then we create the database.

const database = new manager(url, DB_NAME);
database.createDatabase()

The createDatabase returns a promise. In the promise, we will start creating a view for the data.

database.createDesignDocument('main', {
filters: {
year: 'function (doc) { if (doc.year === 2004) { return true;} return false;}'
},
views: {
movies: {
map: 'function (doc) { if (doc.year) { emit(doc._id, null);}}'
}
}
});

After that we start the replication connection with our server, we are going to open a connection from our Server to our local database, and we set the flag to keep open the connection and get the updates of the data in the server.

const REPLICATION_OPTIONS = { continuous: true };
database.replicate(`http://${SG_URL}/${DB_NAME}`, DB_NAME, REPLICATION_OPTIONS);

The next step is to listen for the changes that happen in the database.

database.getInfo()
.then(res => {
database.listen({
since: res.update_seq - 1,
feed: 'longpoll',
});
database.changesEventEmitter.on('changes', function (e) {
this.setState({sequence: e.last_seq});
}.bind(this));
})
.catch(e => console.log('ERROR INFO', e))

The last step is to get the data from the database, we are using view to query it, and we store the data in our component state

  .then(() => database.queryView('main', 'movies', {include_docs: true}))
.then(res => this.setState({
dataSource: this.state.dataSource.cloneWithRows(res.rows),
}))

Rendering

The last step is to render the data in our app.

First, we import the elements we are going to use in our component.

import {
StyleSheet,
Text,
View,
ListView,
Image,
} from ‘react-native’;

As we mention before, we are going to use a ListView component to render all the data

render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
enableEmptySections
/>
</View>
);
}

And we define the function to render the movie data

renderMovie(movie) {
var movie = movie.doc;
return (
<View style={styles.movieContainer}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}

And we add the styles for the components

const styles = StyleSheet.create({
container: {
flex: 1
},
movieContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
seqTextLabel: {
textAlign: 'center',
margin: 5
},
listView: {
flex: 1,
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1,
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81,
},
});

Run the App

Now if we run the application we should see the list of movies.

You may need to start the react native server, for that, run the command in a terminal

react-native start

To run the application, in a terminal run

react-native run-android
Capture of the app running

Notes

If you run the app in an android emulator, you will need to execute the following command to open the port to connect to the sync gateway server

adb reverse tcp:4984 tcp:4984

--

--

Jose Miguel

Software Engineer, traveler. Currently working at Criptan (Spain) from South Korea. You can check about me here https://jmn8718.github.io/