zoukankan      html  css  js  c++  java
  • [技术博客]React-Native中的组件加载、卸载与setState问题

    React-Native中的组件加载、卸载与setState问题。

    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.

    通常我们会在componentWillMount方法中执行异步数据请求,然后调用setState方法处理得到的数据来更新界面。有时会遇到这个警告,如下图:

    警告提示我们可能在被卸载的组件上调用了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()意味着这个组件可能没有被正确的清理掉,也就是说,程序仍然具有对这个被卸载组件的引用,这可能导致内存泄漏。

    以前有一个isMounted()函数用来确定组件的状态,避免在被卸载了的组件上调用setState()方法,但是现在已经不再使用了。

    要解决这个问题,可以维护一个变量_isMounted,来跟踪组件的状态。在componentDidMount()中将其设置为true,在componentWillUnmount()中将其设置为false。然后在使用setState, replaceState, or forceUpdate方法时检查组件被卸载之后是否可能被调用,如果是,则使用_isMounted变量。

    修正后的代码如下。现在再重复前面的操作,在数字数到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++;
                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:

    参考连接:

    【React报错】isMounted is an Antipattern

    isMounted is an Antipattern

  • 相关阅读:
    JZOJ5954.【NOIP2018模拟11.5A组】走向巅峰
    JZOJ5956.【NOIP2018模拟11.7A组】easy LCA
    JZOJ5957.【NOIP2018模拟11.7A组】scarborough fair
    JZOJ5959【NOIP2018模拟11.8A组】铁路运输
    NOIP2018游记
    Pycharm 解释器的快捷键
    计算机编程语言初识
    计算机初识
    Python之如何修改运行的快捷键
    [USACO09NOV]硬币的游戏A Coin Game
  • 原文地址:https://www.cnblogs.com/PureMan6/p/10871932.html
Copyright © 2011-2022 走看看