если setState не может быть использован, чем то, что делает - PullRequest
0 голосов
/ 04 февраля 2019

Я пытаюсь установить состояние пользователя, получая значение из моей базы данных, а затем используя его.По какой-то причине состояние не обновляется само по себе, я пробовал await и async.Какие еще варианты существуют, если этот не может быть надежным, чтобы сделать это значением.

Я получаю следующую ошибку: Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method. - node_modules/fbjs/lib/warning.js:33:20 in printWarning - node_modules/fbjs/lib/warning.js:57:25 in warning - node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:12196:6 in warnAboutUpdateOnUnmounted - node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:13273:41 in scheduleWorkImpl - node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:6224:19 in enqueueSetState - node_modules/react/cjs/react.development.js:242:31 in setState * null:null in componentWillMount$ - node_modules/regenerator-runtime/runtime.js:62:44 in tryCatch - node_modules/regenerator-runtime/runtime.js:296:30 in invoke - ... 13 more stack frames from framework internals

constructor() {
  super();
  this.state = {
    userPhoneNumber: "",
  };
}
async componentWillMount() {
  await firebase.database().ref('/Users/' + firebase.auth().currentUser.uid).on('value', async snap => {
    if (snap) {
      await this._setPhone(snap.val())
    } else {
      this.props.navigation.navigate('Phone')
    }
  });


  console.log(this.state.userPhoneNumber);

}
_setPhone = (snap) => {
  const val = parseInt(snap, 10);
  this.setState({
    userPhoneNumber: val
  })
};

1 Ответ

0 голосов
/ 04 февраля 2019

Если вы уверены, что получаете правильное значение для snap.Тогда проблема в том, что setState является асинхронным.Это означает, что для установки состояния требуется время.

К сожалению, они проверяют ваше состояние, чтобы увидеть, было ли установлено неверное значение.

Вы должны использовать обратный вызов в функции setState, чтобы ваш setState стал:

this.setState({userPhoneNumber: val}. () => console.log(this.state.userPhoneNumber));

Я бы порекомендовал прочитать следующеестатьи Майкла Чана, в которых более подробно рассказывается о настройке состояния

https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0 https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296 https://medium.learnreact.com/setstate-takes-a-function-56eb940f84b6

Есть также несколько проблем с использованием async/await и promises похоже, что вы смешиваете синтаксис между ними.Вы либо используете один или другой, а не оба.Эта статья подробно описывает различия между ними.

this.setState не возвращает обещание, поэтому использование await this.setState ничего не дает.

Вот как я бы реорганизовал ваш код:

componentDidMount() { // componentWillMount is deprecated
  // you are using a promise to access firebase so you shouldn't be using `async/await`
  firebase.database().ref('/Users/' + firebase.auth().currentUser.uid).on('value', snap => {
    if (snap) {
      this._setPhone(snap.val()) // remove the await as it is not doing anything
    } else {
      this.props.navigation.navigate('Phone')
    }
  });
}

_setPhone = (snap) => {
  const val = parseInt(snap, 10);
  this.setState({ userPhoneNumber: val}, () => console.log(this.state.userPhoneNumber)) // include the callback to check the value of state
};

Обновленный вопрос

Вы должны звонить setState, когда компонент был размонтирован.Вы должны убедиться, что ваш компонент смонтирован перед вызовом setState.

Одним из способов сделать это является наличие логического флага, который отслеживает, когда компонент монтируется.

componentDidMount () {
  this._isMounted = true;
}

componentWillMount () {
  this._isMounted = false;
}

когда вы устанавливаете свое состояние, вы можете сделать что-то вроде этого

if (this._isMounted) {
  this.setState({key: value});
}

Вы можете узнать больше об этом здесь https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

Просто установитеСвойство _isMounting имеет значение true в componentDidMount и присвойте ему значение false в componentWillUnmount, и используйте эту переменную для проверки состояния вашего компонента

Это не идеальное решение, но оно самое простое, как вам на самом деле должно бытьотмена ваших обещаний и т. д., так что setState никогда не вызывается, поскольку обещание было отменено.

...