如果不能的setState比不使用

问题描述 投票:0回答:1

我试图通过让从我的数据库的值,然后用它来设置用户的状态。出于某种原因,状态不更新本身我试图等待和异步。如果这个人能不可靠,使这是一个值存在什么其他的选择。

我得到了以下错误: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
  })
};
javascript firebase react-native firebase-realtime-database
1个回答
3
投票

如果您确信您收到的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它看起来像你混合它们之间的语法。你要么使用一个或另一个,而不是两个。这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
};

Updated question

您必须调用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和将其设置为false componentWillUnmount,并使用这个变量来检查你的组件的状态

这难道不是一种理想的解决方案,但它是最简单的,因为你真的应该取消你的承诺等,这样的承诺已经取消了setState永远不会被调用。

© www.soinside.com 2019 - 2024. All rights reserved.