情景描述
-
需求:
- 父组件需要在初始化的时候发送请求获取一个userId的数组
- 父组件需要把获取到的这个数组传递给子组件
- 子组件需要在初始化的时候对父组件传入的数组做循环,循环使用userId发送请求获取user信息
- 子组件将获取到的所有user信息使用列表展现出来
-
实现:
- 在父组件的
componentDidMount
中发送请求获取到userId数组 - 传递给子组件
- 在子组件的
componentDidMount
中循环发送请求获取user信息
- 在父组件的
-
出现问题:
- 发现子组件拿到的userId数组始终未空
解析
Q1:包含父子组件的生命周期经历了怎样的过程
-
A1: 假设有这样的组件结构
class Father extends Component{ componentDidMount(){ console.log('father componentDidMount') } render(){ console.log('father render') return ( <div> <Children1 /> <Children2 /> </div> ) } } class Children extends Component{ componentDidMount(){ console.log('children componentDidMount') } render(){ console.log('children render') return ( <h1>这是子</h1> ) } }
挂载阶段的执行顺序:
- 1.父类的ComponentWillMount
- 2.父类的render
- 3.子类1的ComponentWillMount
- 4.子类1的render
- 5.子类2的ComponentWillMount
- 6.子类2的render
- 7.子类1的ComponentDidMount
- 8.子类2的ComponentDidMount
- 9.父类的ComponentDidMount
得出结论:
- 父类的componentDidMount必须在所有子类的ComponentDidMount之后执行
- 并行子类:先依次执行并行组件的render方法知道最后一个子类的render执行完,再开始从第一个子组件依次执行ComponentDidMount方法
- 错误原因:
- 因为父类的ComponentDidMount比子类的晚,因此父类子类发请求的时候父类还没有发请求拿到userId数组,这时候子类拿到的所有数据都是undefined
- Q2:如何能做到让父类的ComponentDidMount先于子类执行呢?这样是不是可以解决这个问题呢?
- A2:首先这样想问题的出发点就是错的
-
父子的生命周期函数的调用都是同步的
- 就算父的ComponentDidMOunt先执行,ComponentDidMOunt中你发了请求
- 请求需要时间
- 而子类的componentDidMount并不会等待父类的异步请求执行完毕之后再执行
-
- Q3:父类传给子类的值是否子类的任何一个生命周期函数都能拿到呢?
- A3:答案是肯定的,子类可以在自己的任何一个生命周期函数中拿到父类传入的数据
- Q4:可不可以在子类使用componentWillReceiveProps判断父类数据一旦请求到子类立刻发送请求
- A4:这样是好的解决方法,而由于我之前对componentWillReceiveProps的错误理解拒绝使用,误区如下
- 拒绝在所有的will生命周期函数中setState,所以也就不愿意在其中发请求
-
componentWillReceiveProps只会在props类型数据发生改变的时候调用,state属性发生改变永远不会触发
-
- 害怕componentWillReceiveProps会执行很多次出现请求很多次的情况
-
componentWillReceiveProps函数处理数据的时候一定要加上判断,并且判断条件要考虑到两方面
- 第一次可以执行
- 以后不能再执行
-
- 拒绝在所有的will生命周期函数中setState,所以也就不愿意在其中发请求
我的解决方案
- 父类ComponentDidMount发请求
- render中判断数据是否拿到
- 拿到之后再挂载子类组件
- 并且为了保证如果当前组件被封成一个Component之后其他人能够正常使用
- 因此根据无状态组件的特点
- 在当前组件的外层封装无状态组件(用来根据数据是否获取确定组件的加载时机)
- 这时候直接在父类中引入这个无状态组件
- 保证父类不会知道这个组件被延迟加载
其他解决方案
- 父组件仍然在componentDidMount里面发送请求
- 子组件在componentWillReceiveProps中判断数据是否存在
- 存在的话就在子类的componentWillReceiveProps中发送请求