react-native-firestack icon indicating copy to clipboard operation
react-native-firestack copied to clipboard

Exception 'Calls to setPersistenceEnabled must be made before any other usage of FIRDatabase instance.' was thrown while invoking enablePersistence on target FirestackDatabase with params

Open vivekmago opened this issue 7 years ago • 24 comments

I cannot get persistence to work have the following code in my index file but it keeps cribbing about the error.. pls help what am I doing wrong...

const firestack = new Firestack();

firestack.onReady(()=> {
	firestack.database.setPersistence(true);
});

vivekmago avatar Jan 06 '17 17:01 vivekmago

Hello, @vivekmago ! Did you had some issues like this ?

danielcolgan avatar Jan 07 '17 00:01 danielcolgan

I have the same problem in v3. Basically I am doing this:

const firestack = new Firestack();
firestack.database().setPersistence(true);

I guess the problem could be this code in the Database constructor:

this.offsetRef = this.ref('.info/serverTimeOffset');
this.offsetRef.on('value', (snapshot) => {
  this.serverTimeOffset = snapshot.val() || this.serverTimeOffset;
});

This accesses the database immediately, which means that it is not possible to execute setPersistence before. Do you think it is actually needed to have that method, or could it be just an option that can be passed to Firestack like const firestack = new Firestack({ persistence: true }): Does anybody see a use case that would require to switch persistence on/off/on during runtime?

moooji avatar Jan 09 '17 04:01 moooji

Here is a PR that fixes the issue. https://github.com/fullstackreact/react-native-firestack/pull/232

setPersistence has to be called before any database references have been created. Since the database constructor immediately creates refs to .info/serverTimeOffset, calling setPersistence will always throw and it is not possible to enable persistence currently. Furthermore, setPersistence is not part of the Web SDK API anyway.

To fix this issue, this PR makes setPersistence internal and adds instead an option persistence that can be supplied to the Firestack constructor. This guarantees that persistence will be enabled before any refs are created.

const firestack = new Firestack({ persistence: true });

moooji avatar Jan 11 '17 00:01 moooji

@Salakar how do you enable persistence in your code? Can you post a snippet? I have seen this issue with all v3 branches including yours :-/

I am using Using FirebaseDatabase (3.1.1) on iOS, are you using the same?

Also the official SDK docs say about persistenceEnabled on iOS:

Note that this property must be set before creating your first Database reference and only needs to be called once per application.

https://firebase.google.com/docs/reference/ios/firebasedatabase/api/reference/Classes/FIRDatabase#persistenceenabled

That being said, I cannot see how setPersistence could possibly work in v3 if the database constructor immediately creates references. Or do you see a way to call setPersistence before initializing the database?

Additionally, my thought is that an options is more suitable in this case than a method, because of the "[...] only needs to be called once per application."

@auser Are you using the persistence feature? Does it work for you in v3?

moooji avatar Jan 11 '17 19:01 moooji

We just do the following, and import it throughout the app. No issues as far as I'm aware!

import Firestack from 'react-native-firestack';

const firestack = Firestack.initializeApp({
  debug: __DEV__ ? '*' : false,
  errorOnMissingPlayServices: false,
});

/**
 * Enable offline database persistence
 */
firestack.database().setPersistence(true);

export default firestack;

Ehesp avatar Jan 12 '17 07:01 Ehesp

@moooji can you confirm if @Ehesp 's solution works? We're on android only at the moment, but @chrisbianca is on ios and isn't facing this issue also I believe.

Think its a case of we need more docs 👀

Salakar avatar Jan 12 '17 07:01 Salakar

I'm not using .setPersistence() at the moment, so can't confirm either way on iOS.

Based on the docs @moooji is right, you need to call setPersistence before you create anything - perhaps this differs between iOS and Android? Regardless, it would make sense to follow the option approach to work around this as I can't see a reason where you'd want to enable and disable this feature throughout the app.

chrisbianca avatar Jan 12 '17 09:01 chrisbianca

@Salakar I am facing this issue on iOS. I will try @Ehesp 's solution.

esdrasportillo avatar Jan 12 '17 09:01 esdrasportillo

It doesn't work for me, even using @Ehesp 's solution. I am on v3 branch and on iOS.

esdrasportillo avatar Jan 12 '17 11:01 esdrasportillo

Must be iOS specific. I think on Android it wasn't calling it before everything else so there was a fix.

Ehesp avatar Jan 12 '17 12:01 Ehesp

I like the idea that we can set this in the configuration, rather than it's own method.

auser avatar Jan 12 '17 21:01 auser

Given this error on ios what method are you guys using to persist the user state at login? redux persist? Also when this works will it persist the auth state automatically or just the database state? Cheers

@SamMatthewsIsACommonName Database persistence works now on iOS using the latest v3 version and enabling the persistence option like this const firestack = new Firestack({ persistence: true });. This will persist the database state only. In regards to the user / auth persistence, the docs say

When a user signs up or signs in, that user becomes the current user of the Auth instance. The Firebase Auth instance persists the user's state, so that refreshing the page (in a browser) or restarting the application doesn't lose the user's information.

When the user signs out, the Auth instance stops keeping a reference to the User object and no longer persists its state; there is no current user. However, the user instance continues to be completely functional: if you keep a reference to it, you can still access and update the user's data.

So this does not have to do with database persistence and should be handled by the Auth module I think.

UPDATE: I just tried out if auth persistence works in my app and it looks like it does in iOS at least (could not test Android). I signed in with email/password and fetched the token like this:

firestack.auth().getToken()
      .then(token => console.log(token));

Then, I closed the app and reopened it again. Without signing in, I could still fetch the same auth token again, so it looks like it is persisted.

In case there are more questions in regards to user persistence, we should maybe open a dedicated issue about that.

I think we can close this issue.

moooji avatar Jan 14 '17 16:01 moooji

Thanks guys awesome work really appreciate it

Hi @moooji , does it work now? I can't see the commit in the v3 branch and I updated to the latest version and it is still not working. Am I missing something ?

esdrasportillo avatar Jan 16 '17 11:01 esdrasportillo

@esdrasportillo Sorry, I thought that PR https://github.com/fullstackreact/react-native-firestack/pull/232 had been merged, but apparently it has just be closed... Looks like it won't be part of v3 then @auser?

moooji avatar Jan 16 '17 15:01 moooji

@auser @Salakar Persistence on iOS is still broken because the PR has been rejected. What shall we do instead to fix it?

moooji avatar Jan 20 '17 01:01 moooji

Having the persistence as an option through the constructor will make bootstrapping a lot easier, thank you!

However, I'm having hard time figuring out which version PR/commits are part of the current 3.0.0-rc.2 package. I will try to use the v3 branch directly from git instead, but.. would be nice to have v3 tags in this repository for clarity!

rikur avatar Jan 29 '17 03:01 rikur

@rikur I'm also struggling to work out which version has which code, but also which fork to use. @Salakar has merged into his fork a PR which fixes this issue, but a lot of the code in his fork is different to this repo and has quite a different API so I would have to rewrite my app to use it. Have you made any progress either with choosing a fork/version or with getting persistence to work? Thanks very much for your time.

benadamstyles avatar Feb 08 '17 21:02 benadamstyles

See my comment here: https://github.com/Salakar/react-native-firestack/commit/386be3d0b118256ca510bbe78ad21c4748b8f7d9#commitcomment-20812842

chrisbianca avatar Feb 09 '17 07:02 chrisbianca

Thanks for your work @chrisbianca. Are there plans to merge the repos? IMHO it feels not feasible for anybody if there is the "main" repo, but all dev work happens in a separate fork. This is highly confusing for anybody who wants to contribute or use this library.

moooji avatar Feb 14 '17 00:02 moooji

@moooji We know, it's not great and we're just as frustrated that the work we've done has been undermined by some untested PRs. @Salakar @Ehesp and I have been chatting about it and trying to work something out. We'll hopefully have something for you soon...

chrisbianca avatar Feb 14 '17 08:02 chrisbianca

@Salakar @Ehesp @chrisbianca Any news on this?

moooji avatar Mar 12 '17 05:03 moooji

Hello i fixed this problem but it was really hard : follow my steps 👍

  1. Android manifest add in application <application android:name="com."Your path".FireClass"

  2. Create a Fireclass : `public class FireClass extends Application { public static boolean deja = false;

     @Override
     public void onCreate() {
         super.onCreate();
    
         if (!deja)
         {
             FirebaseDatabase.getInstance().setPersistenceEnabled(true);
             //deja = true;
         }
    
         FirebaseDatabase database = FirebaseDatabase.getInstance();
    

Log.d("FIREBASE","INITIALISATION"); } }`

  1. Create a Dbutil.class: youll call him each time you need to run an db query : `public class databaseUtil { public static FirebaseDatabase mDatabase; public static FirebaseDatabase mDatabase22; public static DatabaseReference mDatabase2 ; public static DatabaseReference mDatabase3 ; public static FirebaseAuth mAuth; public static FirebaseAuth.AuthStateListener mAuthListener;

    public static FirebaseDatabase getDatabase() {

     if (mDatabase == null) {
    
         mDatabase = FirebaseDatabase.getInstance();
         mDatabase.setPersistenceEnabled(true);
    
    
         mDatabase2 =mDatabase.getReference("user");
         mDatabase3 =mDatabase.getReference("user");
         mDatabase2.keepSynced(true);
         mDatabase3.keepSynced(true);
    
     }
    
    
     return mDatabase;
    

    } `

  2. on each class you need to do db thing : do declare : private db DatabaseUtil;

[...] On create (){ .... db.getDatabase();

[....] } 5) import mDatabase from DatabaseUtil.class and use them like 👍 mDatabase3.addValueEventListener(new ValueEventListener() { .......

  1. run !

TomCyril1 avatar Jun 29 '18 15:06 TomCyril1