Реагируйте на собственную проблему - инициализируйте состояние, вызвав другой метод из конструктора - PullRequest
0 голосов
/ 03 марта 2019

У меня есть небольшой React Native Component, в котором я пытаюсь инициализировать состояние, считывая значения из локального хранилища (AsyncStorage) .Но когда я вызываю внешний метод из конструктора, я получаю undefined в качестве значения состояния.

Вот часть моего кода:

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

Кто-нибудь знает, как решить эту проблему?Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 03 марта 2019

Есть несколько проблем с кодом, который вы вставили в свой вопрос.

Во-первых, 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 фактически ничего не возвращает.Возвращаемое значение находится внутри обещания.К счастью, мы можем преобразовать функцию для использования 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 теперь истинно, чтобы отобразить правильный вид:

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

Вот некоторые статьи, которые стоит прочитать:

0 голосов
/ 03 марта 2019

Замените

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.Затем посмотрите состояние в рендере, надеюсь, вы увидите правильное состояние.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...