如果不能使用setState而不是

时间:2019-02-04 14:23:54

标签: javascript firebase react-native firebase-realtime-database

我试图通过从数据库中获取值然后使用它来设置用户状态。由于某种原因,状态无法自我更新,因此我尝试了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 :(得分:3)

如果您确定收到的是ccc的正确值。那么您遇到的问题是snap是异步的。这意味着状态设置需要花费时间。

不幸的是,他们用这种方式检查状态以查看是否设置了错误的值。

您应该在setState函数中使用回调,这样您的setState会变成:

setState

我建议您阅读Michael Chan的以下文章,其中更详细地介绍了设置状态

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

使用this.setState({userPhoneNumber: val}. () => console.log(this.state.userPhoneNumber));async/await时还存在一些问题,似乎您在混合使用它们之间的语法。您可以使用其中之一,而不能同时使用两者。 article详细介绍了它们之间的区别。

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

您可以在这里https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html

中查看更多信息
  

只需在componentDidMount中将_isMounted属性设置为true并设置   在componentWillUnmount中将其设置为false,并使用此变量进行检查   您组件的状态

这不是理想的解决方案,但它是最简单的解决方案,因为您实际上应该取消诺言等,因此if (this._isMounted) { this.setState({key: value}); } 永远不会因为诺言被取消而被调用。