Tackling React Native Storage — Part 1

December 12, 2016 0 Comments

Tackling React Native Storage — Part 1



RealmDB, React Native, Firebase, Redux

Making data persist in React Native can be hard. I have worked with AsyncStorage, RealmDB, and Firebase using React Native. Today I am going to cover RealmDB but also briefly touch on AsyncStorage.

If you would like to skip the details and go straight to the example, feel free to check out my github for a simple todo items using realm and redux. https://github.com/bosung90/RNStorage

AsyncStorage is a local storage that gives you the ability to persist data between app restarts. One big advantage of using AsyncStorage is that it requires no additional setup to use as it comes with React Native out of the box. However, downside is that it has slow runtime and has no indexing capabilities. Because AsyncStorage only accepts string as its value, all data must first be serialized into string before being inserted, and deserialized once retrieved. This is why you should not use AsyncStorage when dealing with a large amount of data.

Below is a simple example to store and retrieve a simple JavaScript Object.

import {AsyncStorage} from 'react-native'
const SETTINGSKEY = 'Settings'
const settingsObj = {lastUpdate: 1479396301390, language: 'en', theme: 'dark'}
KEY, JSON.stringify(settingsObj))
const settings = JSON.parse(settingsStr)

When you are dealing with a large amount of data, or simply require a faster local storage, consider using Realm. I have used this database with React Native extensively and I am very happy with it. It is simply much faster than AsyncStorage and SQLite (source: https://realm.io/news/introducing-realm-react-native/). Compared to AsyncStorage, you need to write more lines of code, however, it is totally worth it, as it will save you tonnes of efforts down the line. Unfortunately the documentation and examples are somewhat lacking, so it may take some time to get used to its APIs.

In order to maximize the performance, Realm has decided to go with statically typed database. This means you first need to define the structure of database (using JS classes) before you can add/remove anything to it.

import Realm from 'realm'
class TodoItem {
static get () { return realm.objects(TodoItem.schema.name) }
static schema = {
name: 'TodoItem',
primaryKey: 'id',
properties: {
id: {type: 'string'},
value: {type: 'string'},
completed: {type: 'bool', default: false},
createdTimestamp: {type: 'date'}
// Create Realm DB
const realm = new Realm({schema: [TodoItem]})

Once you create realm, you can now add/remove/update items from it.

Here are some basic operations in Realm.

// Retrieves all todo items in sorted(reversed) order
export const getTodoItems = () => {
const todoItems = TodoItem.get().sorted('createdTimestamp', true)
return todoItems
// Retrieve a single todo item
export const getTodoItem = (id) => {
const todoItem = realm.objectForPrimaryKey(TodoItem, id)
return todoItem
// Update todo item. todoItem parameter must be of Realm.Object
export const updateTodoItem = (todoItem, value, completed) => {
realm.write(() => {
try {
todoItem.value = value
todoItem.completed = completed
} catch (e) {
// Creates a new TodoItem
export const createTodoItem = (value) => {
realm.write(() => {
realm.create(TodoItem.schema.name, {
id: uuid.v1(),
createdTimestamp: new Date()
// Deletes a todo Item. todoItem parameter must be Realm.Object
export const deleteTodoItem = (todoItem) => {
realm.write(() => {

So far, I have covered very basic things that you can easily figure out by reading the official realm documentation.

Before I continue on, please take a quick look at the official documentation. https://realm.io/docs/javascript/latest/ . Once you are more familiar with Realm, I suggest you read it again so you don’t miss anything out. I also found API reference page to be extremely useful https://realm.io/docs/javascript/latest/api/ as it covers many functions that get started guide does not.

From now on, I will list out some of the tips that I have learned through using realmDB for the past year. You should refer to my github project to see how to do this in action. (https://github.com/bosung90/RNStorage)

I have started using Redux extensively for the past year. Redux works wonderfully together with Realm. The reason is because whenever you change the data stored in Realm, it always goes through the redux dispatch. This means you no longer have to subscribe to changes to Realm to know when to refresh the UI.

This is also extremely important, and applies for any database you might want to use. Benefits of doing this will be that when you want to change to a different database (for example Realm to Firebase), it will be extremely easy. Another way to put it will be that you want to decouple Realm with your container components, they don’t need to know that the data is coming from Realm or Firebase (or even hard coded data). This also allows you to combine multiple data sources into a single data stream.

Simply create a folder store and create index.js that combines all data sources into one.

import * as realm from './realm'
import * as asyncStorage from './asyncStorage'
export default {

Your container components now only need to import store.

Caution: When you want to reference anything inside store, such as store.createTodoItem following will not work!

// This will fail, createTodoItem will be undefined
import {createTodoItem} from '../store'
// This will work
import store from '../store'
const {createTodoItem} = store

The reason is import (unlike require) gets resolved during compile time, but createTodoItem is not available until runtime. Just stick to store.createTodoItem or use de-structuring.

Realm comes with their own version of ListView, which optimizes the performance if Realm.Results is used as ListView.DataSource, but has exactly same API as React Native ListView.

First, you do not need to create instance of ListView.DataSource every time. A good place to put it would be in the same file where you define your RealmDB class.

import { ListView } from 'realm/react-native'
export const todoItemDS = new ListView.DataSource({rowHasChanged: (r1, r2) => r1.id !== r2.id})

Note: I return true whenever id is different as that is my primaryKey for TodoItem class.

According to Realm getStarted guide, Realm.Results is auto-updating. However, you still need to update the UI because React does not know that Realm.Results has been updated. Auto-updating means you simply do not have to re-fetch the data from the realm database.

// Realm.Results is auto-updating, therefore no need to re-fetch the data
const todoItemsResults = store.getTodoItems()
const mapStateToProps = (state, props) => ({
dataSource: store.todoItemDS.cloneWithRows(todoItemsResults)
const mapDispatchToProps = {
export default connect(mapStateToProps, mapDispatchToProps)(TodoItems)

Note that I still need to cloneWithRows every time my UI updates.

The reason why I don’t need to manually refresh the UI is because my redux action causes redux-store state to change which causes my UI to update.

// actions.js
export const createTodoItem = (todoText) => {
return {
type: 'TODO
export const deleteTodoItem = (todoItem) => {
return {
type: 'TODO
// reducers/todoItems.js
STATE = {}
export default (state = DEFAULTSTATE, {type, payload} = {}) => {
switch (type) {
case 'TODO
case 'TODO
return {...state, lastModified: Date.now()}
return state

That is it! I hope you learned something useful from this post. Like and share if you think others will be able to benefit from it too.

In part 2, I will cover Firebase but it will be much shorter than this post.

If you want to know more about the navigation / redux check out my previous blog post. https://medium.com/@bosung90/tackling-react-native-navigation-with-react-native-router-flux-and-redux-27fcd86fb2b7


Tag cloud