学习笔记230827--vue项目中,子组件拿不到父组件异步获取数据的问题

🧋 问题描述

父组件的数据是请求后台所得,因为是异步数据,就会出现,父组件的值传递过去了,子组件加载不到,拿不到值的问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pn9unWDw-1693103033395)(https://note.youdao.com/yws/res/9/WEBRESOURCE717fc88846ccc13c044a1e223126def9)]

下面从同步数据传递和异步数据传递开始论述问题

🧋🧋1. 父组件传递的是同步数据
  • 父组件

        <template> 
         <div class="parent">
            <div class="child">
                 <props-children :data="dataJson"></props-children>
            </div>
            <input type="text"  v-model="dataJson"/>
         </div>
      </template>
      
      <script>
      import propsChildren from '../../component/props/props_children.vue'
      export default {
        components: { propsChildren },
        
        data(){ 
          return{
              dataJson:"初始化数据"
          }
        },
         created(){
           console.log('父created',this.dataJson)
         },
         beforeuUpdate(){
           console.log('父beforeupdated',this.dataJson)
         },
         updated(){
            console.log('父updated',this.dataJson)
         },
         beforeDetroy(){
            console.log('父beforeDetroy',this.dataJson)
         },
         detroyed(){
            console.log('父detroyed',this.dataJson)
         }
      }
      </script>
      
      <style scoped>
       
      .child{
          width:600px;
          height:600px;
          
          background:#eee;
      }
      </style>
    
  • 子组件

    
      <template>
          <div>
              我是子组件<br><br><br>
              获取到父组件数据:{{data}}<br><br><br>
              <input type="text"  v-model="data"/>
          </div>
      </template> 
      
      <script>
      export default {
         mounted(){
            console.log('子组件拿到数据',this.data)
         },
         props:{
              data:{
                  default:"",
                  require:true,
                  type:String
              }
            
         },
         created(){
           console.log('子created',this.data)
         },
         beforeUpdate(){
           console.log('子beforeupdated',this.data)
         },
         updated(){
            console.log('子updated',this.data)
         },
         beforeDetroy(){
            console.log('子beforeDetroy',this.data)
         },
         detroyed(){
            console.log('子detroyed',this.data)
         }
      }
      </script>
      
      <style>
      
      </style>
    

如图所示:

  • 在created阶段,父组件的初始化数据就已经传递给了子组件的props

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qATnm0VP-1693103033400)(https://note.youdao.com/yws/res/1/WEBRESOURCEef9e584f878538fed9af15b7ffaba1e1)]

  • 在created阶段,把获取的同步数据赋值给初始化数据,不会触发update钩子函数,子组件加载也能拿到数据

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jfcWIjPZ-1693103033403)(https://note.youdao.com/yws/res/4/WEBRESOURCE405319a84ce951d33284d54e96c59304)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hh2isRv4-1693103033405)(https://note.youdao.com/yws/res/a/WEBRESOURCE9d4d920a472804c230ba7a9e6e35e28a)]

  • 父组件更新数据(触发update),子组件也会同步更新,但是先更新的是子组件里的数据

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xEj4L6Jj-1693103033407)(https://note.youdao.com/yws/res/4/WEBRESOURCEb3e3c88a52735c3328ae1a51de1f7e74)]

  • 子组件去更新props里的数据,父组件不但接收不到,而且还会报错

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vAQlqToa-1693103033409)(https://note.youdao.com/yws/res/6/WEBRESOURCE01aa38076fe0445148a42c134336fa56)]

父子组件声明周期执行顺序

加载渲染数据过程

父:beforeCrete --> 父:created --> 父:beforeMount --> 子:beforeCreate --> 子:created --> 子:beforeMount --> 子:mounted --> 父:mounted

更新渲染数据过程

父:beforeUpDate --> 子:beforeUpdate --> 子:updated --> 父:updated

销毁组件数据过程

父:beforeDestroy --> 子:beforeDestroy --> 子:destroyed --> 父:detroyed

但是,如果父组件获得是后台请求的异步数据就会出现问题。

🧋🧋 2.父组件传递的是异步数据
  • 父组件
<template>
   <div class="parent">
      <div class="child">
           <props-children :data="dataJson"></props-children>
      </div>
      <input type="text"  v-model="dataJson"/>
   </div>
</template>

<script>
import propsChildren from '../../component/props/props_children.vue'
export default {
   components: { propsChildren },
   data(){ 
    return{
        dataJson:"初始化数据"
    }
   },
   created(){
     // 模拟获取后台异步数据
     setTimeout(()=>{
        this.dataJson="父组件数据"
     },200)
     console.log('父created',this.dataJson)
   },
   beforeUpdate(){
     console.log('父beforeupdated',this.dataJson)
   },
   updated(){
      console.log('父updated',this.dataJson)
   },
   beforeDetroy(){
      console.log('父beforeDetroy',this.dataJson)
   },
   detroyed(){
      console.log('父detroyed',this.dataJson)
   }
}
</script>

<style scoped>
 
    .child{
        width:600px;
        height:300px;
        
        background:#eee;
    }
</style>
  • 子组件
<template>
    <div>
        我是子组件<br><br><br>
        获取到父组件数据:{{data}}<br><br><br>
        <input type="text"  v-model="data"/>
    </div>
</template> 

<script>
export default {
   mounted(){
      console.log('子组件拿到数据',this.data)
   },
   props:{
        data:{
            default:"",
            require:true,
            type:String
        }
      
   },
   created(){
     console.log('子created',this.data)
   },
   beforeUpdate(){
     console.log('子beforeupdated',this.data)
   },
   updated(){
      console.log('子updated',this.data)
   },
   beforeDetroy(){
      console.log('子beforeDetroy',this.data)
   },
   detroyed(){
      console.log('子detroyed',this.data)
   }
}
</script>

<style>

</style>
 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vuRVJklG-1693103033410)(https://note.youdao.com/yws/res/a/WEBRESOURCE246c2ee57a93411eadd80b789a82321a)]
【产生问题的原因】
父组件异步获取后台数据, 这时候加载渲染数据生命周期已经走完,只能更新数据,触发更新渲染生命周期,所以子组件加载时,永远只能拿到父组件的初始数据,拿不到父组件更新后的数据,但是,但是props是可以等的,页面是可以拿到异步的数据渲染的,所以就出现如上所示 的结果。

🧋解决问题
如何子组件加载获取不到父组件异步获取数据的问题
  • 方案1:使用v-if控制子组件渲染的时机,父组件拿到后台异步数据后,再渲染子组件,加载子组件的时候就能得到父组件 的异步数据。

  • 方案2:子组件使用watch监听父组件传递过来的数据。

    这种方式父组件正常传递数据即可,不要做什么代码处理,只要在子组件中加一个监听即可。

🧋问题总结

子组件props如果绑定动态数据,默认只在加载时传递,也就是说只传一次。props绑定视图层,可以传多次。父组件created赋值同步数据不会触发updated,同步数据可以在created时就传递给子组件。父组件赋值异步数据,触发update,子组件也会在update才能拿到数据,所以加载时只能拿到父组件的初始化数据。