vue父组件传数据给子组件,子组件watch这个数据第一次有效,刷新页面就无效(同时解决请求数据时间过长,导致子组件过早渲染而无法获取到最新数据的问题)

需求&问题

  • 本文废话有点多,但我觉得有些业务场景应该也会有人遇到,索性还是把需求和问题都写详细点,看各位路过的朋友不说能解决你的问题,哪怕是对你有一点点帮助的,我也就很高兴了的😂,嫌废话多的,直接看图应该就懂我的意思,我只留了关键的代码…

问题1:本来是要向后台请求数据的,但是由于数据过大,后台需要处理,所以整个请求时间过长,可是我就是要拿到这个请求数据传给子组件,但实际上假如请求时间需要5s,而子组件渲染完成只需要3s,那就取不到数据了,我想到的解决办法有:

法1: 在子组件使用watch去监听这个传来的props,如代码:

父组件:

// 父组件的template
<template>
   <assessChart :num="num"></assessChart>
</template>

// 父组件的methods
 nextSycDetail({ qid: this.qid }).then((res) => {
        if (res.data === null) {
          return;
        }
        this.num = res.data; // 这个num就是要传给子组件的 props
     }

子组件:

// 子组件的props
props:["num"]

// 子组件的watch
watch:{
 num:{
   deep:true,
   handler(newVal){
   		// TODO
		console.log("子组件接收到了参数...")
	}
  }
}

法2: 使用vuex,就是将这个num属性放在vuex里面,然后夫组件请求数据成功后,把数据赋给vuex里的num,再在子组件直接访问vuex里面的num就行了。

总结

共同点: 两者都是通过响应式的原理,去监听属性的变化,当请求结束之后,这个值就会变,一变也就是我拿到的请求后的数据了,然后再去做对应的操作
优缺点: 推荐法1,因为法1是通过父子组件通信来传值的,传递的更加直接,也更加好理解;然而法2的话,你不仅要引入vuex来做中间者,虽然在实际项目中确实也很常用,引入到没什么,最麻烦的一点就是,你刷新页面的话,这个vuex它是会重新创建实例的,里面的数据又没了,也许作为开发者知道要避免刷新,那别人用户呢??他哪管你这些,他只知道页面有些东西没出来,就习惯性的去刷新一下,那你这样不就出问题了??除非你本地存储一份,刷新的时候更新一下vuex,不过这样岂不是又多了一个步骤??又增加了业务?


问题2
上面的问题解决了,由于我的需求是有下一个的操作的,比如说我当前访问的数据A的信息,当用户点击下一个应该访问的是数据B的信息,可是用户在这个时候刷新页面,用户想看到的是数据B的信息,而不是数据A的信息,可刷新的话,我接口又是访问的数据A的信息,这个没办法避免,因为这个接口的参数必须是从其他页面带过来的,所以我就做了一个本地存储的操作,也就是说当这个页面进来时,我会做一个判断,看用户是第一次进来页面还是后续刷新页面,第一次进来的话,我就正常请求接口,渲染页面,并本地存储一份; 如果是后续做了刷新操作,那我就从本地存储拿数据,这样子就可以保证不管你是一进就刷新,还是点了下一个再刷新,都是可以拿到用户想要的数据了。

可问题就是刷新页面的话,我父组件传给子组件num确实也是最新的了,但就是子组件的watch监听不到,因为数据没有变化,即使我在num赋值前做了一个作弊的方法,就是随便给个值,比如

// 父组件的methods
nextSycDetail({ qid: this.qid }).then((res) => {
        if (res.data === null) {
          return;
        }
        localStorage.setItem("sycDetail", JSON.stringify(res.data)); // 本地存储一份
        this.num = null; // 作弊方法也没用
        this.num = res.data; // 这个num就是要传给子组件的 props
     }

就是类似这样,想着强行让它数据变化,结果在子组件里面的watch还是监听不到,不过在子组件里面created或者mounted生命周期里面去进行如下操作

// 子组件的created或者mounted,这里以created为例
created(){
   this.num = JSON.parse(localStorage.getItem("sycDetail"));
}

但是这样是vue禁止的,不建议去直接修改父组件传来的props的,控制台也会报错,虽然你可以在子组件里面的data里面去另外取一个变量,假如为:num_zi,然后把传来的num赋值给num_zi,再在created或者mounted里面去进行
this.num_zi = JSON.parse(localStorage.getItem("sycDetail"));,紧接着再去watch这个num_zi变量,看似可以,但是我试过也是不行,也许是我手法不对把,还请路过的大佬指教。。。。

最终解决办法
在子组件中watch这个传来的num的时候加一个属性immediatetrue,即:
子组件:

watch:{
	num:{
		deep: true,
		immediate: true,
   		handler(newVal){
	   		// TODO
			console.log("子组件接收到了参数...")
		}
	}
}

说明:
(1)immediate属性设置为true时,在watch中首次绑定的时候立即执行handle函数。
(2)immediate属性设置为false时,和使用普通方式一样,只有在数据发生变化的时候才执行handler。

官方说明:
在这里插入图片描述

综上所诉:在子组件watch监听父组件传的数据,并加上immediate属性

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值