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

本文探讨了解决React子组件在每次进入时重新请求数据的问题。通过利用componentWillReceiveProps方法,结合状态管理和条件判断,确保了数据的及时更新,避免了不必要的重复请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

        今天写了个父子组件的嵌套,有个需求是每次进入子组件都重新请求数据。但是,我的父组件是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.youkuaiyun.com/wangchenggggdn/article/details/79759171

                  https://blog.youkuaiyun.com/huanghanqian/article/details/80721575

 

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

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

### React Native 组件生命周期方法及其调用顺序 React Native 的组件生命周期可以划分为四个主要阶段:创建阶段、实例化阶段、运行(更新)阶段以及销毁阶段。以下是这些阶段中的具体生命周期方法及其调用顺序: #### 1. **创建阶段** 在这个阶段,组件类被定义,静态属性被设置。 - `getDefaultProps` 如果存在,则在此阶段会被调用来设定默认的 props 值[^4]。需要注意的是,在 ES6 类语法中,这个方法已经被废弃,推荐通过直接声明 static 属性来实现相同功能。 #### 2. **实例化阶段** 当组件第一次渲染时会经历此阶段,它包含了以下几个重要的生命周期方法: - `constructor(props)` 构造函数会在组件实例化时执行一次,用于初始化 state 或绑定事件处理程序。这是第一个被执行的方法。 - `static getDerivedStateFromProps(nextProps, prevState)` 此静态方法在首次渲染前和每次重新渲染之前都会被调用,允许我们基于新的 prop 更新状态。 - `componentWillMount` (已废弃) 在首次渲染之前立即调用,但在服务器端渲染期间不会被调用。由于其不可预测的行为,官方建议避免使用该方法,并考虑迁移到其他替代方案。 - `render()` 返回描述 UI 结构的 JSX 元素或 null。它是唯一一个必须实现的方法。 - `componentDidMount()` 当组件已经加载到 DOM 中之后立刻调用。通常在这里发起网络请求或者订阅数据源。 #### 3. **运行(更新)阶段** 每当组件接收到新 Props 或 State 变更时进入此阶段。 - `shouldComponentUpdate(nextProps, nextState)` 默认返回 true;如果希望优化性能可以通过覆盖此方法控制何时需要重绘界面。 - `getSnapshotBeforeUpdate(prevProps, prevState)` 在最近的一次渲染输出提交到 DOM 前调用,可用于捕获一些信息供后续操作使用。 - `componentWillUpdate` (已废弃) 即将在下一版本移除,请改用上述提到的新 API 替代旧版钩子函数。 - `render()` 同上,再次渲染视图结构。 - `componentDidUpdate(prevProps, prevState, snapshot?)` 在组件完成更新后调用,适合做日志记录或其他副作用逻辑。 #### 4. **销毁阶段** 当组件不再需要显示给用户时就会触发卸载过程。 - `componentWillUnmount()` 在组件即将被从 DOM 移除前调用,清理定时器、取消网络请求或是解除事件监听等资源释放工作应该放在这里面进行处理。 ```javascript class MyComponent extends React.Component { constructor(props) { super(props); this.state = { /* 初始化state */ }; } componentDidMount() { console.log('组件挂载'); } shouldComponentUpdate(nextProps, nextState) { return nextProps.someValue !== this.props.someValue || nextState.someOtherValue !== this.state.someOtherValue; } componentDidUpdate(prevProps, prevState) { console.log('组件更新完毕'); } componentWillUnmount() { console.log('组件即将卸载'); } render() { return ( <View> {/* 渲染内容 */} </View> ); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值