S. M. Asif
S. M. Asif

Reputation: 3709

Where to call AsyncStorage.getItem( ) function to load saved data in react-native?

I have saved one data inside one class of my react-native project. With saving data I start a new screen. In that screen I am retrieving that saved data. For that purpose, I call AsyncStorage.getItem('token') function inside the render function.

Here is the code for that class-

import React from 'react';
import { StyleSheet, Text, View, Image, AsyncStorage } from 'react-native';
import {Icon, Button, Container, Header, Content, Left} from 'native-base';
import CustomHeader from './CustomHeader';

 class NoteMeHome extends React.Component {
  state = {
    text:'',
    storedValue:'',
    getValue: ''
  };

  static navigationOptions = ({navigation}) => ({
    title: "Home",
    headerLeft: <Icon name="ios-menu" style={{paddingLeft:10}}
    onPress={()=>navigation.navigate('DrawerOpen')}/>,

    drawerIcon: 

    <Image source={require('../assets/icon.png')}
            style={styles.icon}
    />
  })

  render() {
    const {storedValue} = this.state;

    AsyncStorage.getItem('token').then(value =>
      //AsyncStorage returns a promise so adding a callback to get the value
      this.setState({ getValue: value })
      //Setting the value in Text 
    );

    return(
      <Container>
        <CustomHeader
          title="Home"
          drawerOpen={()=>this.props.navigation.navigate('DrawerOpen')}
        />
        <Content contentContainerStyle={{flex:1, alignItems:'center', 
        justifyContent:'center', padding:10}}>
        <Button full onPress={()=> this.props.navigation.navigate('Settings')}>
          <Text style={{color:'white'}}>{storedValue}</Text>
        </Button>
        <Text>{this.state.getValue}</Text>
        </Content>
      </Container>
    )
  }

}

const styles = StyleSheet.create({
  icon:{
    height: 24,
    width: 24
  }
})
export default NoteMeHome;

After that, while running the project, in the above mentioned class, when I click any of my drawer items to go to another screen, it shows the following error in the console-

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

I guess something goes wrong with AsyncStorage.getItem('token') function calling because if I remove the function it doesn't show any warning.

So, it would be very nice if someone helps me to know where should I call the following code-

AsyncStorage.getItem('token').then(value =>
  //AsyncStorage returns a promise so adding a callback to get the value
  this.setState({ getValue: value })
  //Setting the value in Text 
);

to remove the warning ?

Upvotes: 2

Views: 2810

Answers (3)

Shivam
Shivam

Reputation: 3131

In react component render() should always remain pure. One should never set state in render function, it a very bad pracice, in a simple component it might work fine. It only works because of the asynchronicity.

You should use componentDidMount lifecycle method to fetch data from local storage.

componentDidMount() {
    const token = await AsyncStorage.getItem('token');
    this.setState({ getValue: token });
}

Upvotes: 0

tagkiller
tagkiller

Reputation: 340

Asif,

Here is what I had in mind :

import React from 'react';
import { StyleSheet, Text, View, Image, AsyncStorage } from 'react-native';
import {Icon, Button, Container, Header, Content, Left} from 'native-base';
import CustomHeader from './CustomHeader';

 class NoteMeHome extends React.PureComponent {
  state = {
    text:'',
    storedValue:'',
    getValue: ''
  };

  static navigationOptions = ({navigation}) => ({
    title: "Home",
    headerLeft: <Icon name="ios-menu" style={{paddingLeft:10}}
    onPress={()=>navigation.navigate('DrawerOpen')}/>,

    drawerIcon: 

    <Image source={require('../assets/icon.png')}
            style={styles.icon}
    />
  });
  
  componentDidMount() {
    const token = await AsyncStorage.getItem('token');
    this.setState({ getValue: token });
  }

  render() {
    const {storedValue, getValue} = this.state;
    return(
      <Container>
        <CustomHeader
          title="Home"
          drawerOpen={()=>this.props.navigation.navigate('DrawerOpen')}
        />
        <Content contentContainerStyle={{flex:1, alignItems:'center', 
        justifyContent:'center', padding:10}}>
        <Button full onPress={()=> this.props.navigation.navigate('Settings')}>
          <Text style={{color:'white'}}>{storedValue}</Text>
        </Button>
        <Text>{getValue}</Text>
        </Content>
      </Container>
    )
  }

}

const styles = StyleSheet.create({
  icon:{
    height: 24,
    width: 24
  }
})
export default NoteMeHome;

I don't know if in your case you should actually try to handle the update of the component since you don't have any props.

Regards,

Upvotes: 1

MPN7
MPN7

Reputation: 1313

IMO you should use componentDidMount for anything that you want to do in the beginning of a screen. To use AsyncStorage remember that is an asynchronous function so you have to wait for the function to complete so you can get the value.

For more information about react native's components please see this

For more information about 'waiting' for AsyncStorage using async please see this examples

Upvotes: 0

Related Questions