1

I'm making a mobile app in React-Native where the user must login first to use the functionalities. If the user logs in succesfully, I save the username with AsyncStorage.setItem, which works great.

I try to get the value on app start using AsyncStorage.getItem, using the code:

class LoginScreen extends Component { 

   static PropTypes = {
      dispatch: PropTypes.func,
      fetching: PropTypes.bool,
      attemptLogin: PropTypes.func
   }

   isAttempting = false

   constructor (props) {
     super(props)

      this.state = {
        username: '',
        password: '',
        isLoaded: {false}
      }

   }

   componentDidMount(){
     const { username, password } = this.state
     this._getSavedUsername(); 

     // AsyncStorage
     //   .getItem('@MobAppCorpStore:username')
     //   .then((v_username) => { this.setState({ username: v_username, isLoaded: true  }) });

   }

   async _getSavedUsername() {
     const { username } = this.state

     try {
       const value = await AsyncStorage.getItem('@MobAppCorpStore:username');
       if (value !== null){
         this.setState({ username: value});
       }
     } catch (error) {
       // Error retrieving data
       alert('Containers/LoginScreen - _getSavedUsername error')
       console.log('Containers/LoginScreen - get username error : ', error)
     }
   }

   ...

   render () {
      ...

      <Form style={styles.form_style}>
         <Item floatingLabel >
            <Label>{I18n.t('Global.username')}</Label>
            <Input 
                  style={styles.input_style} 
                  //autoFocus = {true}
                  returnKeyType='next'
                  value={username} 
                  onChangeText={username => this.setState({username})}
                  autoCapitalize="none"
                  blurOnSubmit={false}
                  />
         </Item>
         <Item floatingLabel last >
            <Label>{I18n.t('Global.password')}</Label>
            <Input 
                  style={styles.input_style} 
                  returnKeyType='go'
                  secureTextEntry={true} 
                  value={password} 
                  onChangeText={password => this.setState({password})}
                  onSubmitEditing={this._handlePressLogin}
                  autoCapitalize="none"/>
         </Item>
       </Form> 

       ...
   }

   ... 

}

The value is correctly recovered and displayed in the TextInput (Input from NativeBase). But I also get this error:

Warning: Can't call setState (or forceUpdate) on an unmounted component. 
This is a no-op, but it indicates a memory leak in your application. To fix, 
cancel all subscriptions and asynchronous tasks in the componentWillUnmount 
method.

If I understood correctly, AsyncStorage is an async function, so the value is recovered "later", after the lifecycle in this case?

What is the correct way to get a value using AsyncStorage at the start of an app/screen?

(I've already seen this post What is the correct way to use AsyncStorage to update state in React-Native? but I think it's not similar to my case)

geometrikal
  • 3,195
  • 2
  • 29
  • 40
Gaetan B.
  • 21
  • 4

1 Answers1

0

The problem you are experiencing is probably caused by you are trying to send parameter inside get item username. If you want to save your keys as '@MobAppCorpStore:username' syntax you should use something like this @MobAppCorpStore:${username}

let name = "John" 
let point = "100"
try {
  await AsyncStorage.setItem(`@MobAppCorpStore:${name}`, point);
} catch (error) {
  // Error saving data
}

And by using your key you can get the value of latest

try {
  const grade = await AsyncStorage.getItem(`@MobAppCorpStore:${name}`);
  if (value !== null){
    // We have data!!
    console.log(value);
  }
} catch (error) {
  // Error retrieving data
}
suchcodemuchwow
  • 848
  • 2
  • 9
  • 27
  • Thanks for this tips. But it's not really the problem (the value are correctly saved and recovery) The question is rather : where/when do "this.setState(username: myRecoveredValue)" to avoid this error : Can't call setState (or forceUpdate) on an unmounted component. – Gaetan B. May 09 '18 at 08:37
  • Are you navigating to other screen ? Because you can't set state on unmounted component maybe you can try componentWillUnmount but because of AsyncStorage.getItem is not sync operation you will probably face with same issue. Just try to navigate or whatever you are doing to unmount component after, AsyncStorage.getItem operation & setting the returned value to state – suchcodemuchwow May 09 '18 at 11:59
  • No I'm not trying to navigate (because this is the login screen). I try to fill the input text "Username" with the recovered value. So the user only has to enter his password. (the username is saved at first succesfull login) – Gaetan B. May 09 '18 at 12:54
  • Can you please check this example the logic is same but only with font load https://docs.expo.io/versions/latest/guides/using-custom-fonts I haven't tried it for your case. Probably conditional rendering and async version of componentDidMount fix your issue. – suchcodemuchwow May 09 '18 at 13:17
  • I've followed the logic of this example on a standalone app, and it's working fine. But, when I reproduce it on my app, I keep the same error. May be it's "caused" by something else ? (ignite, navigation, redux ... ) – Gaetan B. May 13 '18 at 09:14