【问题标题】:if setState cant be used than what does如果 setState 不能使用比什么
【发布时间】:2019-02-04 14:23:53
【问题描述】:

我试图通过从我的数据库中获取一个值然后使用它来设置用户的状态。由于某种原因,状态不会自行更新,我尝试过等待和异步。如果此选项不可靠以使其成为一个值,还有哪些其他选项。

我确实收到以下错误: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
  })
};

【问题讨论】:

  • 这很奇怪。它应该工作。不过这里不需要awaitawait this._setPhone(snap.val())
  • 请输入有效的JS类语法,为什么用await调用this._setPhone()
  • 添加了 await 作为使这项工作都不起作用的另一种尝试
  • 您在导航离开后在某处设置状态,请确保您不这样做。您可能忽略了这个组件的关键部分,很难说在哪里。
  • 您在此代码中不需要任何asyncawait,因为我看到您使用的是回调方法,您应该使用componentDidMount 而不是componentWillMount,然后再一次,请提供有效的类语法,以确保您的问题与其他问题无关

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


【解决方案1】:

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

不幸的是,您正在检查您的状态以查看设置的值是否错误。

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

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

我建议阅读 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

您对async/awaitpromises 的使用也存在一些问题,看起来您正在混合它们之间的语法。您要么使用其中一个,要么使用另一个,而不是两者。这个article 详细介绍了它们之间的差异。

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

只需在 componentDidMount 中将 _isMounted 属性设置为 true 并设置 它在componentWillUnmount中为false,并使用这个变量来检查 你的组件的状态

这不是一个理想的解决方案,但它是最简单的,因为你真的应该取消你的承诺等,这样setState 就不会因为承诺被取消而被调用。

【讨论】:

  • 感谢您的回答,这就是为什么我添加了等待以使其使用回调设置将不允许我继续使用组件中接下来的几行所需的值将安装
  • 更新了我的答案
  • 使用“isMounted”策略是次优的,更好的方法是取消订阅componentWillUnmount()中的firebase事件,这将允许对卸载的实例进行垃圾收集并避免内存泄漏。
  • @Lennholm 我确实提到这不是一个理想的解决方案。
猜你喜欢
  • 1970-01-01
  • 2019-10-23
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
相关资源
最近更新 更多