关于react-native中生命周期componentWillReceiveProps多次调用的原因

版权声明:原创文章,未经允许不得转载!!! https://blog.csdn.net/halo1416/article/details/81737443

前言:

        今天写了个父子组件的嵌套,有个需求是每次进入子组件都重新请求数据。但是,我的父组件是app的首页,并且是一个tabView,子组件是其中的一个tab页。我把数据请求写在了 componentWillMount 方法里,发现他只会调用一次,再次进入时并不会触发,就是进入到其他页面后返回首页再次进入这个tab页,componentWillMount也不会被触发。原因是:因为父组件是没有的卸载的,而 componentWillMount 在一次生命周期内只能被调用一次,除非父组件经历了 componentWillUnmount 这个生命周期方法,完成了一个生命周期的过程,再次进入时 componentWillMount 方法才会被触发。

寻找解决方法:

        react 生命周期中有一个 componentWillReceiveProps(nextProps) 方法,用于在子组件的render函数执行前获取新的props,其中接受一个参数是nextProps:为父组件传过来新的props,而 旧的属性还是可以通过this.props来获取!

问题:

        componentWillReceiveProps这个方法在父组件的第一次render时是不会被调用的,但是我发现在其余时候:父元素的render函数被调用,子组件就会触发componentWillReceiveProps,不管props有没有改变。

        我的父组件是一个tabView,每次切换tab时会导致state中的 curPage (当前页)的变化,从而是render会被再次调用。所以导致了componentWillReceiveProps在首次时执行了一次(父组件的第一次render时是不会被调用的,而state的变化导致调用了一次);其余时候componentWillReceiveProps都会被调用两次。

        props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用  ===>>> 这是官方的componentWillReceiveProps的介绍

           这样虽然componentWillReceiveProps调用了多次,但是render是通过this.setState来更新的。所以比较安全。而且可以在componentWillReceiveProps手动判断props是否发生了变化,从而考虑是否执行componentWillReceiveProps的回调。

注:tabView事例

但是:

          我的项目中props是没有任务变化的,并且我还有调用componentWillReceiveProps的回调函数(请求数据),这个就需要自己设置变量做判断了!(我的方法比较笨,大佬们有简单方法的希望多多指教,对了,还可以 shouldComponentUpdate 控制哦,但是我对shouldComponentUpdate不是很熟悉,准备有时间在研究研究)

解决代码:

let num = 1;

export class MineScreen extends Component{
    constructor() {
        super();
        this.state = {
            personInfo : {},        //用户信息
            loading : false,        //是否加载数据
        }
    }

    // componentWillMount(){
    //     this.loadData();        //第一次进入
    // }

    //该组件是作为子组件引用的,并且需要每次进入刷新界面,所以需要用componentWillReceiveProps
    //componentWillReceiveProps除了首次调用一次以外,其余都会调用两次
    componentWillReceiveProps(nextProps){
        if(num <= 2) {              //首次进入为1
            this.setState({loading: false,});           //取消loading显示,下次进入在加载数据前显示

            this.loadData();
            num++;              //触发componentWillReceiveProps后将num++,而在请求会将num都设为了2,在+1为3,componentWillReceiveProps将只调用一次
        }
    }

    async loadData(){
        try{
            let result = await API.config.personinfo('111');
            this.setState({
                personInfo : result,
                loading : true,
            });
            num = 2;            //每次请求数据后将num设为2
        }catch (err) {
            showToast(err.message);
        }
    }
}

解决思路:设置一个全局变量num,默认值为1,每次调用请求函数loadData后将其设置为2,在 componentWillReceiveProps 方法里面判断 num <= 2 才去调用loadData方法,并且在调用之后num++(其实只要大于 2 就行)。

代码执行顺序:

第一次:父组件中调用子组件时,componentWillReceiveProps没有被触发,但是因为state的变化导致父组件的render被重新调用并导致子组件的componentWillReceiveProps被触发,但num这事为1,所以加载了一次数据(请求)!

非第一次:此时父组件中调用子组件时,componentWillReceiveProps会被触发,并且因为state的变化,componentWillReceiveProps会被再次调用(即总共调用两次),但是第一次调用是num=2,满足条件,但在componentWillReceiveProps中调用loadData方法之后,将num++(不满足条件了),所以这个生命周期中componentWillReceiveProps只能被调用一次!  但是,在执行loadData方法时,又将num设为了2,所以下次进入时num还是为2!!

参考博客:https://blog.csdn.net/wangchenggggdn/article/details/79759171

                  https://blog.csdn.net/huanghanqian/article/details/80721575

文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出

对博客文章的参考,若原文章博主介意,请联系删除!请原谅

猜你喜欢

转载自blog.csdn.net/halo1416/article/details/81737443