Отрисовка компонента после получения значения от AsyncStorage в React Native

My React Component хранит пользовательские настройки в AsyncStorage и получает их при загрузке. Хранение и получение данных работают хорошо, но есть проблема, которую компоненты обрабатывают до того, как значения были получены из асинхронной функции. Как это можно было исправить? Это мой код:

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;

person anDev    schedule 29.07.2020    source источник
comment
У меня будут значения по умолчанию в компоненте, а затем передать их, как только функция async будет завершена. Таким образом, он будет повторно отображаться после обновления.   -  person rhigdon    schedule 29.07.2020
comment
В общем, если вы не получили требуемые параметры для компонента перед его рендерингом, вам, вероятно, следует использовать условный рендеринг в этом компоненте (т.е. проверить, присутствуют ли требуемые параметры, если они есть, рендерить нормально, если они нет, визуализировать загрузку или ноль)   -  person ttous    schedule 29.07.2020
comment
@rhigdon, я пробовал переместить this.state[i] = Media.initalSettings[i] перед вызовом функции async, но ничего не изменилось   -  person anDev    schedule 29.07.2020
comment
Вы никогда не должны устанавливать состояние напрямую. Вам следует использовать вспомогательную функцию setState.   -  person rhigdon    schedule 29.07.2020
comment
@rhigdon, спасибо за совет, я думал, что вызов setState запрещен в конструкторе компонента, но я изменил this.state[i] = value на this.setState({key: value}) после получения данных, и он работал правильно. Вы можете написать ответ, и я отмечу его как решение   -  person anDev    schedule 29.07.2020


Ответы (2)


Похоже, вы пытаетесь установить состояние прямо в конструкторе. Попробуй это:

  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})
          }
        }
      );
    }
  }

Вот некоторая документация: https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly.

person rhigdon    schedule 29.07.2020

ваш конструктор слишком загроможден.

инициализировать пустую переменную состояния и заполнять ее при загрузке страницы

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>
  )
}
person Karan Wadhwa    schedule 29.07.2020