itinance
itinance

Reputation: 12428

ReactNative: best approach to share a sqlite-instance across all components and actions

The story:

In a react-native app we use react-native-sqlite-storage for dealing with sqlite3 both on iOS and Android.

This plugin enable us to deal with native sqlite implementation in that way:

var db = SQLite.openDatabase("test.db".....);

What would be the best approach to share the db-instance across multiple components? To give more details, but this is not part of this question, we use redux and have many action-files. Some of them need access to the database too.

In order to deal with a single opened instance of sqlite across all components and actions, and also to being more loosely coupled from native components, i built a class DataStorage encapsulating the storage-plugin. This class holdes an instance of the sqlite-database (using the react-native-sqlite-storage) and provides convenient methods to the application like "getUserByName()", "getAllItems" and so on.

To avoid multiple instances of this DataStorage class and also its inner sqlite-db-instance, i did the following:

  1. build the DataStorage class
  2. create a global variable residing only in DataStorage.js
  3. export a function sharedDataStorage() to the all the callers which need database access

Code of DataStorage.js

const SQLite = require('react-native-sqlite-storage');

const _dataStorage = null;

export class DataStorage {

    constructor(autoCheckMigration = true, lang = 'en') {
        console.log("DataStorage CTOR called");

        if(_dataStorage !== null) {
            throw 'There is already an instance of DataStorage alive';
        }

        // store this instance in a global variable
        _dataStorage = this;

        this.db = SQLite.openDatabase('myapp.db', '1.0', 'Myapps Database', 5 * 1024 * 1024, this.openCB, this.errorCB);

        if (autoCheckMigration) {
            this.checkDatabaseMigration(lang);
        }
    }

    many_other_convenience_methods_here(...) {}
}

export function sharedDataStorage() {
    return _dataStorage;
}

Applications root component:

In the applications root component i create the database instance calling its constructor.

export default class Application extends React.Component {

    constructor(props) {
        super(props);

        this.setupDatabase();
    }

    render() {
        return (
            <Provider store={store}>
                    <ApplicationContainer />
          </Provider>
        );
    }

    setupDatabase() {
        this.setState( {dataStorage: new DataStorage()} );
    }
}

Some action_...js:

All other components and action-files now must gain access to this DataStorage-Class in this way:

import { sharedDataStorage } from '../data/dataStorage';

...

async function persistContacts(contacts) {
    const dataStorage = sharedDataStorage();

    contacts.forEach( (contact) => {
        dataStorage.persistContact(contact);
    });
}

This way is working pretty fine, although i am not sure, if there are better approaches sharing a database connection in react-native.

Which other possibilities are there?

Upvotes: 14

Views: 6696

Answers (1)

Marco
Marco

Reputation: 1493

I solve in this way:

database.js

'use strict';
import React from 'react';
import SQLite from 'react-native-sqlite-storage';


var database_name = "dbname.db";
var database_version = "1.0";
var database_displayname = "db";
var database_size = 200000;

let conn = SQLite.openDatabase(database_name, database_version, database_displayname, database_size, openDBHandler, errorDBHandler);

class Database  {
    getConnection() {
        return conn;
    }
}

module.exports = new Database();

Next in your component you can get the database connection with:

var connection = Database.getConnection();

Upvotes: 17

Related Questions