React-Native中的组件加载、卸载与setState问题。html
Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.react
一般咱们会在componentWillMount方法中执行异步数据请求,而后调用setState方法处理获得的数据来更新界面。有时会遇到这个警告,以下图:react-native
警告提示咱们可能在被卸载的组件上调用了setState()方法。通常状况下是在某个异步请求还未结束时组件被卸载了,但请求完毕后按照仍会按照正常流程调用setState()方法,这时就出现了上面的警告。网络
下面用一段代码来复现这种状况。为了方便,不使用真正的网络请求,而是使用下面的count()方法。count()方法每隔1秒调用一次setState方法将this.state.count加1,总共调用10次setState()方法。这样就有充足的时间来观察和操做。异步
在render()方法中,将this.state.count这个数字显示在屏幕中央。componentWillMount方法中调用count方法,组件准备加载时就开始计数,至关于进行异步的网络请求。在跳转到这个页面后,屏幕中央的数字会从0一直加到10,在加到10以前,退出这个页面,就能观察到上图所示的警告。函数
import React, { Component} from 'react'; import { View, Text, } from 'react-native'; export default class Test extends Component { constructor(props) { super(props); this.state = { count: 0, } } x = 0; count = () => { if (this.x < 10) { this.x++; this.setState({count: this.x}); setTimeout(this.count, 1000); } } componentWillMount() { this.count(); } render() { return ( <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}> <Text style={{fontSize: 40}}>{this.state.count}</Text> </View> ) } }
实际上,这个警告能帮助咱们找到程序中的bug,在一个被卸载的组件上调用setState()意味着这个组件可能没有被正确的清理掉,也就是说,程序仍然具备对这个被卸载组件的引用,这可能致使内存泄漏。flex
之前有一个isMounted()函数用来肯定组件的状态,避免在被卸载了的组件上调用setState()方法,可是如今已经再也不使用了。this
要解决这个问题,能够维护一个变量_isMounted,来跟踪组件的状态。在componentDidMount()中将其设置为true,在componentWillUnmount()中将其设置为false。而后在使用setState, replaceState, or forceUpdate方法时检查组件被卸载以后是否可能被调用,若是是,则使用_isMounted变量。code
修正后的代码以下。如今再重复前面的操做,在数字数到10以前退出页面,就不会出现警告了。component
import React, { Component} from 'react'; import { View, Text, } from 'react-native'; export default class Test extends Component { constructor(props) { super(props); this.state = { count: 0, } } x = 0; count = () => { if (this.x < 10) { this.x++; if (this._isMounted) { this.setState({count: this.x}); } setTimeout(this.count, 1000); } } _isMounted; componentWillMount() { this.count(); } componentWillUnmount() { this._isMounted = false; } componentDidMount() { this._isMounted = true; } render() { return ( <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}> <Text style={{fontSize: 40}}>{this.state.count}</Text> </View> ) } }
无isMounted:
有isMounted:
参考链接: