我试图通过从数据库中获取值并使用它来设置用户的状态。由于某些原因,状态不会自行更新,我尝试了等待和异步。如果这一个不能可靠地使其成为一个价值,还有什么其他选择。
我确实得到以下错误: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
})
};
如果您确信收到了正确的snap
值。那么问题是setState
是异步的。这意味着状态的设置需要时间。
不幸的是,它们会让你检查自己的状态,看看设置的值是否错误。
您应该在setState
函数中使用回调,这样您的setState
就会变成:
this.setState({userPhoneNumber: val}. () => console.log(this.state.userPhoneNumber));
我建议你阅读一下Michael Chan的以下文章,这些文章将详细介绍设置状态
https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296https://medium.learnreact.com/setstate-takes-a-function-56eb940f84b6
async/await
和promises
的使用也有一些问题——看起来您在混合它们之间的语法。你要么用一个,要么用另一个,而不是两者都用。这篇文章详细介绍了它们之间的区别。
this.setState
不返回promise,因此使用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
就永远不会被调用,因为承诺已经被取消。