问题描述
我有一个小的React Native组件,在其中我尝试通过从本地存储(AsyncStorage)读取值来初始化状态。 但是,当我从构造函数调用外部方法时,我得到的未定义为状态值。
这是我的代码的一部分:
constructor(props) {
    super(props);
    this.state = {
       languageChecked: I18n.locale, 
       anonymityChecked: this.pickLocalKey('anonymity', true), 
       locationChecked: this.pickLocalKey('location', false),  
       notificationChecked: this.pickLocalKey('notification', false),
       statisticsChecked: this.pickLocalKey('statistics', false),
    };
    console.log("STATE: " + this.state.anonymityChecked); // UNDEFINED
}
pickLocalKey(key, defaultValue) {
  AsyncStorage.getItem(key).then((value) => {
    const item = (value !== null && value !== undefined) ? value : defaultValue;
    console.log(item);
    return item;
  });
}
有谁知道如何解决这个问题? 先感谢您
1楼 
  
    Andrew 
    2 
   已采纳 
    2019-03-03 16:16:40
  
 
 您在问题中粘贴的代码存在多个问题。
 
     首先, constructor是同步的,您尝试在其中执行异步任务。 
     这不是一个好主意。 
 
     如果您需要从AsyncStorage加载值并将其存储为state ,则应在componentDidMount 
 
     因此,请在构造函数中设置初始值,并添加一个附加值loaded: false 。 
     这将在以后变得很重要。 
constructor (props) {
  super(props);
  this.state = {
    languageChecked: I18n.locale,
    anonymityChecked: true,
    locationChecked: false,
    notificationChecked: false,
    statisticsChecked: false,
    loaded: false // <- add this additional value
  };
}
 
     当前,您的pickLocalKey函数实际上未返回任何内容。 
     返回值被困在一个Promise中。 
     幸运的是,我们可以将函数转换为使用async/await 。 
     所以它应该看起来像这样: 
pickLocalKey = async (key, defaultValue) => {
  try {
    let value = await AsyncStorage.getItem(key);
    const item = (value !== null && value !== undefined) ? value : defaultValue;
    return item === 'true'; // this will make sure we get a Boolean back as long as you store strings 'true' and 'false' for your Booleans
  } catch (error) {
    return defaultValue;
  }
}
 
     请注意, await可能会抛出,因此始终最好将其包装在try/catch 。 
 
     然后在您的componentDidMount您应该进行调用以从AsyncStorage检索值 
async componentDidMount () {
  // these won't throw as we are catching the error before it gets here
  let anonymityChecked = await this.pickLocalKey('anonymity', true);
  let locationChecked = await this.pickLocalKey('location', false);
  let notificationChecked = await this.pickLocalKey('notification', false);
  let statisticsChecked = await this.pickLocalKey('statistics', false);
  // set all items in state in one go as multiple calls to setState are not good
  this.setState({
    anonymityChecked,
    locationChecked,
    notificationChecked,
    statisticsChecked,
    loaded: true . // <- we set loaded to true
  }, () => console.log(this.state)); // this is how you check state after it has been set
}
 
     然后,在render您现在应该使用loaded现在为true的事实来渲染正确的视图: 
render () {
  if (this.state.loaded) {
    return (
      this is the view that you actually want to show
    )
  } else {
    return (
      this is the view that you will show when everything is loading
    )
  }
}
以下是一些值得阅读的文章:
2楼 
  
    Subhendu Kundu 
    0 
    2019-03-03 15:47:42
  
 
 更换
pickLocalKey(key, defaultValue) {
  AsyncStorage.getItem(key).then((value) => {
    const item = (value !== null && value !== undefined) ? value : defaultValue;
    console.log(item);
    return item;
  });
}
与
constructor(props) {
    super(props);
    this.pickLocalKey('anonymity', true, 'anonymityChecked');
    this.pickLocalKey('location', false, 'locationChecked');
    this.pickLocalKey('notification', false, 'notificationChecked');
    this.pickLocalKey('statistics', false, 'statisticsChecked')
    this.state = {
    };
}
pickLocalKey = (key, defaultValue, stateKey) => {
  AsyncStorage.getItem(key).then((value) => {
    const item = (value !== null && value !== undefined) ? value : defaultValue;
    console.log(item);
    this.setState({
     [stateKey]: item
    });
  });
}
render() {
 console.log(this.state);
}
编辑:所以问题是这是一个承诺,现在构造函数运行一次,而不要等待您的承诺解决。 同样,您不能也不想使您的构造函数成为一个承诺。 一旦取回数据,就无法设置数据。 但是您先调用该函数,然后再执行setState。 然后查看渲染中的状态,希望您会看到正确的状态。