Render component after getting value from AsyncStorage in React Native

Viewed 1553

My React Component stores user's settings in the AsyncStorage and get's them on load. The storing and getting data works well, but there is a problem that components renders before the values has been got from the async function. How this could be fixed? This is my code:

import React from 'react';
import { View } from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import { Media } from '../constants';

class SettingsScreen extends React.Component {
  
  constructor(props) {
    super(props);
    const settings = ['appLanguage', 'colorTheme'];
    for(const i of settings) {
      this.getData(i).then(
        value => {
          if(value === null || value === undefined) {
            this.state[i] = Media.initalSettings[i];
          }
          else {
            this.state[i] = value;
          }
        }
      );
    }
  }

  async storeData(key, value) {
    try {
      if(key[0] != '@') {
        key = '@' + key;
      }
      await AsyncStorage.setItem(key, value);
    } 
    catch(e) {
      console.warn(e);
    }
  }

  async getData(key) {
    try {
      if(key[0] != '@') {
        key = '@' + key;
      }
      const value = await AsyncStorage.getItem(key);
      return value;
    } 
    catch(e) {
      console.warn(e);
    }
  }

  render() {

    const { appLanguage } = this.state;

    return (
      <>
        <View>
          {appLanguage}
        </View>
      </>
    )
  }
}

export default SettingsScreen;
2 Answers

your constructor is way too cluttered.

initialize an empty state variable and populate it when page loads

constructor(props){
  super(props)
  
  this.state = {
    storedValue = ""
  }
}

async componentDidMount() {
  const storedValue = await AsyncStorage.getItem("settings");
  this.setState({storedValue})
}

render(){
  return (
    <View>
      <Text>{storedValue}</Text>
    </View>
  )
}

It looks like you are trying to set the state directly in the constructor. Try this:

  constructor(props) {
    super(props);
    const settings = ['appLanguage', 'colorTheme'];
    for(const i of settings) {
      this.getData(i).then(
        value => {
          if(value === null || value === undefined) {
            this.state[i] = Media.initalSettings[i];
          }
          else {
            this.setState({key: value})
          }
        }
      );
    }
  }

Here is some documentation: https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly

Related