Mobx: Correct way to use observable/computed with AsyncStorage token?

Created on 22 Jul 2016  路  4Comments  路  Source: mobxjs/mobx

In React Native, I am using AsyncStorage to store the token on successful login, and remove it on successful logout using MobX actions in my AuthenticationStore.

I am trying to use a computed value, isAuthenticated which should be derived from the observable token. The token will either be null, if it does not exist in AsyncStorage, or be the AsyncStorage's token item value.

Here is some code to demonstrate:

class AuthenticationStore {
  constructor() {
    tokenStoredValue = AsyncStorage.getItem('token').then((data) => {
      if(!data) { return null; }
      else {return data; }
    });
  }

  @observer token = this.tokenStoredValue;
  @computed get isAuthenticated(){
    return this.token ? true : false;
  }

  @action login(){
    // more code above, here is the relevant setting of token
    this.token = token;
    AsyncStorage.setItem('token', token);
  }

  @action logout() {
    this.token = null;
    AsyncStorage.removeItem('token');
  }
}

In my RN component, I have these 2 alerts to test this:

{AuthenticationStore.isAuthenticated && alert('Logged In')}
{!AuthenticationStore.isAuthenticated && alert('Logged Out')}

The issue is they alert after each other, I think because of the constructor/observer/computed combo of handling this situation. I think I have it setup incorrectly. Also, when I refresh the application Cmd+R in the simulator, after a logout, it alerts that I am logged in, so doesn't care about the tokenStoredValue...

What I am after is to check AsyncStorage for token, if it exists, then the @observable token should equal the stored token, and the isAuthenticated should be true. Otherwise, @observable token should be null and isAuthenticated should be false, and ofcourse only the one respective alert should alert based on isAuthenticated.

How can I get it to work?

Most helpful comment

I would do it like this:

class AuthenticationStore {
  constructor() {
    isAuthenticating = true
    AsyncStorage.getItem('token').then(action((data) => {
      this.token = data
      this.isAuthenticating = false
    }))
  }

  @observable isAuthenticating = false
  @observable token = null
  @computed get isAuthenticated () {
    return this.token ? true : false
  }

  @action login () {
    invariant(!this.isAuthenticating, 'Cannot login while authenticating.')
    invariant(!this.isAuthenticated, 'Cannot login while authenticated.')

    this.isAuthenticating = true

    // more code above, here is the relevant setting of token

    this.token = token
    this.isAuthenticating = false
    AsyncStorage.setItem('token', token)
  }

  @action logout () {
    invariant(!this.isAuthenticating, 'Cannot logout while authenticating.')
    invariant(this.isAuthenticated, 'Cannot logout while not authenticated.')

    this.token = null
    AsyncStorage.removeItem('token')
  }
}

All 4 comments

I would do it like this:

class AuthenticationStore {
  constructor() {
    isAuthenticating = true
    AsyncStorage.getItem('token').then(action((data) => {
      this.token = data
      this.isAuthenticating = false
    }))
  }

  @observable isAuthenticating = false
  @observable token = null
  @computed get isAuthenticated () {
    return this.token ? true : false
  }

  @action login () {
    invariant(!this.isAuthenticating, 'Cannot login while authenticating.')
    invariant(!this.isAuthenticated, 'Cannot login while authenticated.')

    this.isAuthenticating = true

    // more code above, here is the relevant setting of token

    this.token = token
    this.isAuthenticating = false
    AsyncStorage.setItem('token', token)
  }

  @action logout () {
    invariant(!this.isAuthenticating, 'Cannot logout while authenticating.')
    invariant(this.isAuthenticated, 'Cannot logout while not authenticated.')

    this.token = null
    AsyncStorage.removeItem('token')
  }
}

@ronag Thank you, refactoring the code worked.

@ronag what is the "action" . i am getting error .action is not defined

Was this page helpful?
0 / 5 - 0 ratings