50

I'm new in react native.I want store multiple small small strings to common singleton object class and want to access it from singleton object for all component. Can anyone help me singleton object implementation for react native.

Ex

Component 1 -- Login button -- >> success --> need to store userID into singleton object.

Component 2 --> get stored userID from singleton object. How can i implement it.

Ravindhiran
  • 5,304
  • 9
  • 50
  • 82

5 Answers5

83

Here is a simple way of doing it...

export default class CommonDataManager {

    static myInstance = null;

    _userID = "";


    /**
     * @returns {CommonDataManager}
     */
    static getInstance() {
        if (CommonDataManager.myInstance == null) {
            CommonDataManager.myInstance = new CommonDataManager();
        }

        return this.myInstance;
    }

    getUserID() {
        return this._userID;
    }

    setUserID(id) {
        this._userID = id;
    }
}

And here is how to use it...

import CommonDataManager from './CommonDataManager';


// When storing data.
let commonData = CommonDataManager.getInstance();
commonData.setUserID("User1");


// When retrieving stored data.
let commonData = CommonDataManager.getInstance();
let userId = commonData.getUserID();
console.log(userId);

Hope this works out for you :)

Simon B.
  • 2,530
  • 24
  • 30
Yeshan Jay
  • 1,403
  • 1
  • 9
  • 18
  • suppose if i quit the app & reopen the app need to get the stored userID from singleton object how can i do this? – Ravindhiran Jul 04 '17 at 05:58
  • In that case, you'll have to implement to persist data in the setter method. You could try `AsyncStorage`. What I have done above is an In-memory temporary storage. You could also check out this.. [react-native-storage](https://github.com/sunnylqm/react-native-storage) – Yeshan Jay Jul 04 '17 at 08:29
  • I am not able to create using above code. It is crashing on line let commonData = CommonDataManager.getInstance(); – Sujit Oct 12 '17 at 05:25
  • then change the `let` keyword to `var` and see.. i think it's an older version of js engine. – Yeshan Jay Oct 16 '17 at 09:37
  • 3
    There is a typo. It should be `return this.myInstance;` – Pablo Albaladejo Feb 10 '18 at 17:25
  • Thanks so much. This class is very useful for me ! – Shinichi Aug 31 '18 at 02:23
  • I can't believe I've spent all afternoon reading articles about Context, passing Properties, setting variables on the Window object using interface (none of which work!), and this is the first time I've seen `static` - you're a life saver! – Morvael Mar 17 '20 at 15:38
12

I suggest making a static class that stores data using AsyncStorage. You mentioned in a comment that you are already using AsyncStorage, but don't like spreading this functionality throughout your app. (i.e. try-catches all over the place, each component needing to check if a key is available, etc.) If this functionality were in a single class, it would clean up your code a lot.

Another bonus to this approach is that you could swap out the implementation pretty easily, for example, you could choose to use an in-memory object or AsyncStorage or whatever and you would only have to change this one file

NOTE: AsyncStorage is not a safe way to store sensitive information. See this question for more info on the security of AsyncStorage and alternatives.

That said, this is how I imagine a global data holder class might look:

export default class dataManager {
  static storeKeyValue(key, value) {
    // your choice of implementation:
    // check if key is used
    // wrap in try-catch
    // etc.
  }

  static getValueForKey(key) {
    // get the value out for the given key
  }

  // etc...
}

Then to use this class anywhere in your app, just import wherever it's needed like so:

import dataManager from 'path/to/dataManager.js';

// store value
dataManager.storeKeyValue('myKey', 'myValue');

// get value
const storedValue = dataManager.getValueForKey('myKey');

EDIT: Using Flux, Redux, or a similar technology is probably the preferred/suggested way to do this in most cases, but if you feel the Singleton pattern works best for your app then this is a good way to go. See You Might Not Need Redux

David Schumann
  • 13,380
  • 9
  • 75
  • 96
Danny Harding
  • 1,666
  • 19
  • 25
  • In my opinion Redux / Flux is a terrible system. I had a look at it and I just don't see why you would ever use it, as opposed to just encapsulating states of different Models in a singleton. You just need to write so much unnecessary code with Redux, plus you have to have switch statements for actions etc. It's unnecessarily over complicated in my opinion, and does basically the same thing as what the singleton pattern does for you. – Lenka Pitonakova Feb 12 '20 at 18:40
4

There is a workaround for this, react native packager require all the modules in the compilation phase for a generating a bundle , and after first require it generates an internal id for the module, which is from then on referenced in the whole run-time memory , so if we export an instance of a class from the file, that object will be referenced every-time whenever that file is imported .

TLDR;

Solution I :

class abc {

}


module.exports = new abc()

Solution II : I assume you want to get your strings which are static and wont change , so you can declare them as static and access them directly with class name

FYI :this works with webpack also.

David Schumann
  • 13,380
  • 9
  • 75
  • 96
Arnav Yagnik
  • 782
  • 1
  • 4
  • 14
  • Ex I have two component. Component 1 -- Login button -- >> success --> need to store userID into singleton object. Component 2 --> get stored userID from singleton object. How can i implement it. suppose if i quit the app & reopen the app need to get the stored userID from singleton object. – Ravindhiran Jun 23 '17 at 11:35
  • for this purpose i would suggest you use http://facebook.github.io/react-native/releases/0.45/docs/asyncstorage.html#asyncstorage AsyncStorage , this provides you with persistent storage analogous with localStorage in browser. it will store values in the sandbox and you can access it after quitting and re-opening. – Arnav Yagnik Jun 23 '17 at 12:05
  • currenly i'm using AsyncStorage only that is lengthy code I have n number of component class each class need to check AsyncStorage key available & try catch handling is any other alternative solution ? – Ravindhiran Jun 23 '17 at 12:48
  • well the above solution i proposed should work , i am not sure about the case of quitting the app and relaunching it , it might work and is a neater solution , if you try let me also know. – Arnav Yagnik Jun 23 '17 at 12:55
  • did you think to implement redux? – marco.marinangeli Jun 23 '17 at 18:57
4

I might be too late for this, but I might as well share my own implementation based on Yeshan Jay's answer.

export default class Data {

    static instance = null;
    _state = {};
    static get inst() {
        if (Data.instance == null) {
            Data.instance = new Data();
        }
        return this.instance;
    }
    static get state() { 
        return Data.inst._state; 
    }
    static set state(state) { 
        Data.inst._state = state; 
    }
    static setState(state) { 
        Data.inst._state = {...Data.inst._state, ...state} 
    }
}

And here's how you use it. It's pretty much mimicking React Component's state behavior, so you should feel at home with little to no adjustment, without the need to frequently modify the Singleton to add new properties now and then.

import Data from './Data'

// change the whole singleton data
Data.state = { userId: "11231244", accessToken: "fa7sd87a8sdf7as" } 

// change only a property
Data.setState ({ userId: "1231234" }) 

// get a single property directly
console.log("User Id: ", Data.state.userId) 

// get a single property or more via object deconstruction
const { userId, property } = Data.state
console.log("User Id: ", userId) 
Chen Li Yong
  • 5,459
  • 8
  • 58
  • 124
3

TS Class Example:

export class SingletonClass
{
    private static _instance: SingletonClass;

    public anyMetod(_value:any):any
    {
         return _value;
    }
    public static getInstance(): SingletonClass
    {
        if (SingletonClass._instance == null)
        {
            SingletonClass._instance = new SingletonClass();
        }
        return this._instance;
    }
    constructor()
    {
        if(SingletonClass._instance)
        {
            throw new Error("Error: Instantiation failed: Use SingletonClass.getInstance() instead of new.");
        }
    }
}

Use:

SingletonClass.getInstance().anyMetod(1);