User object is null in offline mode
Closed this issue · 19 comments
When offline, the only possibility to get user object is with: MeteorStore.getState().
When trying to reach it like another collection in the properties of a component, it is 'null'.
Try with 1.1.13. It shouldn't be null unless you're not signed in.
Ok I'll test right now.
Very quick :)
No, it is still null.
When I disconnect the server ('Disconnected from DDP server.'), the user is still detected. But as soon as I refresh the react native app, user is null.
It happens only with the 'users' collection.
Did you try in the example, or do you have a repo that I can test? It works for me in the example (if you go to "Profile").
BTW, in case you don't already know about it, there's a preference pane for osx called "Link Conditioner" that allows you to quickly test network connectivity, without jumping on and off wifi.
No I didn't try in the example, but I will in 7 hours when I'm back home.
I also have a repo, I will give it to you but I need to commit tonight.
Oh I didn't know this spec, perfect cheers for the info !
I just tested with the example and it doesn't work (with the version 1.1.13).
The user is not persisted offline (still null).
I have added console.log(user); line 28 in index.js file (RNApp).
Then disconnected the meteor server.
Then refreshed the RNApp.
[FIXED]
I don't think this is a good pattern, but I have replaced user: Meteor.user(),
by user: Meteor.collection('users').findOne()
in createContainer
and the user object is persisted offline.
I'll take a look, but in the meantime that's not a bad solution. react-native-meteor
does that on the backend, I believe.
Ok I think I got it.
Actually the problem is not your package but the react-native-meteor
one (User.js file).
When you do a Meteor.user() if it doesn't find a this._userIdSaved, it returns null.
if it finds it, it returns this.collection('users').findOne(this._userIdSaved).
user() {
if(!this._userIdSaved) return null;
return this.collection('users').findOne(this._userIdSaved);
}
This is exactly the same with Meteor.userId():
userId() {
if(!this._userIdSaved) return null;
const user = this.collection('users').findOne(this._userIdSaved);
return user && user._id;
}
The this._userIdSaved
is defined when login, maybe we should ask to contributors of this repo to set one more item (result.id at the first login on the app) in the Asyncstorage:
_handleLoginCallback(err, result) {
if(!err) {//save user id and token
AsyncStorage.setItem(TOKEN_KEY, result.token);
Data._tokenIdSaved = result.token;
this._userIdSaved = result.id;
Data.notify('onLogin');
} else {
Data.notify('onLoginFailure');
this.handleLogout();
}
Data.notify('change');
},
That makes sense. So, the _handleLoginCallback
should be fine, it's the _loginWithToken
that calls it in a callback from a Meteor.call
, which then requires a connection. Probably best would be to call _handleLoginCallback
from initMeteorRedux
. Thoughts?
Yeah I think you're right, calling _handleLoginCallback()
would be the best option.
Huh, this is tricky... The userId is obtained from the Meteor.call
, not from AsyncStorage, so I can't pass the required parameters. Ideas?
Yeah a bit complicated ...
Why not just create 2 functions in your package for now like:
user() {
return Meteor.collection('users').findOne();
}
and
userId() {
const user = Meteor.collection('users').findOne();
return user && user._id;
}
It will avoid going through this._userIdSaved
.
It won't make us in trouble because there will be only one user using the app (normally).
And then asking for react-native-meteor contributors to register this._userIdSaved in the asyncstorage ...
If you have more than one user, is that guaranteed to return the logged in user?
With autopublish package I don't know. (I think it should work)
But if you remove it, then you just have to create a custom publish for user data:
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId});
} else {
this.ready();
}
});
In fact I think it works in every cases, even without the above snippet
But I mean if you have multiple users, how do you know the user you get back is the logged in one? You could have 100 users and it could return any random one, couldn't it?
You have the const TOKEN_KEY = 'reactnativemeteor_usertoken';
that is stored on the Asyncstorage. So it is linked to a unique userId.
Then, once you're connected you will get info of the user connected with the token, even if there are 100 other users on the database
I added MO.user()
in v2.2.0