Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue父组件异步获取数据并props传给子组件,但是子组件没有及时更新的问题 #19

Open
lizhongzhen11 opened this issue Mar 6, 2019 · 0 comments
Labels
源码 源码

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Mar 6, 2019

问题来源

  记得第一次用vue开发项目时,曾经遇到过父组件调接口改变data里面的某个属性值并通过props传递给子组件,但是子组件并没有实时刷新的问题,当时试了下用watch监听,就解决了。当时初学,vue不怎么懂,更别说源码了,最近项目中又出现过一次这种情况,这就很奇怪了,我必须要解决这个问题。

示例:https://blog.csdn.net/d295968572/article/details/80810349 PS:这是网上其他人的问题,大致与我一样。

思考及查看源码

  根据我提出的问题,可以意识到,这种情况props传过来没有及时更新,但是watch监听却能获取到数据,那么watchprops之间有什么区别呢?官方文档也说父组件动态改变props值,子组件是能获取到的,但是我这里为何不行呢?

  根据上面问题,我先去查看关于props以及watch的源码,其实以前有阅读过watch源码,知道它最终会走defineReactive方法进行观察。但令我没想到的是,props最终也走这个方法。。。

  关于这两个初始化,可以去state.js里面找initPropsinitWatch方法。

  再回顾一下initWatch方法,它内部调用了createWatcher方法(PS:computed初始化也走这个方法了),盖凡凡最终返回vm.$watch(expOrFn, handler, options),而$watch就在下面stateMixin方法内,stateMixininstance/index.js 中执行。$watch里面执行了const watcher = new Watcher(vm, expOrFn, cb, options)这段代码,其实就是实例化了一个Watcher

  然后Watcher里面调用get方法,get方法中调用pushTargetpushTarget在dep.js里,对Dep.target赋值,接着继续看Watcher里面的get方法,这里直接value = this.getter.call(vm, vm),最后return value了。这里就很奇怪,这样看下来根本没有涉及到依赖监听机制啊,按道理不对啊。

  而且,我们只会对props以及在data里面初始化(或者通过this.$set设置)的属性进行watch,但是这里并没有判断被watch的属性是否存在this实例上,也没有判断被watch的属性是不是observe的,难不成我随便瞎写一个属性进行watch也行?

看示例:

如上图,即使被watch的属性并不存在,watch也能执行,只是undefined罢了!

这只是其中的一个小插曲,回到问题上来。

那么,如何实现依赖监听的呢?由于有之前阅读源码的基础,我记得最终watch也是要执行defineReactive的,他在哪里执行的呢?

答案是initDatainitProps里面,其中initData里面铁定调用observe进行观察,Observer中又会生成新的Dep实例,并通过walk方法执行defineReactive

defineReactive里面又生成新的Dep实例,到了这个方法大家没差别,说明props传递进来的值改变也会通知其他依赖的,那么为何watchcomputed能拿到异步调用接口的数据而props不行呢?

他们间的区别在哪呢?我觉得应该是Watcher区别,watchcomputed都实例化了Watcher,但是props没有,网上都说可能接口获取到数值时,组件mounted以经执行完了,所以子组件获取不到。咋一听有点道理,这句话说得其实是对的。

我觉得可能分两种情况(都跟异步获取数据有关):
1.子组件在mounted里面拿到props传值并赋值改变,如果父组件通过接口获取,但是拿到数据时子组件mounted已经执行完了,这时候不会再走mounted进行赋值了,所以发现页面是没变化,这是一个时机问题
2.不在mounted里面赋值,但是,编辑进入时,从媒体那边拿到数据的接口有时候非常慢,那么一进入页面第一视觉可能展示的是默认页面,这时候会误认为有问题,但是当接口获取到数据后页面变为正常,所以这里最好做一个loading效果以免错认为bug

但是watch和props的区别在哪里呢?(也可以认为是computed和data区别)
watch和data以及props最大的区别应该是当数据响应式改变时,watch能拿到新旧值,只要发生变化就会触发并拿到新旧值,而data和props只能被动接受值改变,当需要值改变时触发其他方法时,computed以及watch更合适。
例如最近做的易直投,腾讯这条线计划分为:普通计划、微信朋友圈和微信公众号计划,微信朋友圈和普通计划进入单元页对应的区域定向数据源也不一样,都需要通过接口拿到,而编辑进入单元时,首先需要调接口获取计划类型,然后在根据计划类型去获取数据源,这时候我只能通过computed或者watch监听去判断该调哪个接口获取数据。这里就需要watch的回调了。

具体可以看相关源码:



其实源码里面注释也说了,当被watch的值改变时,会提供回调。。。。。。

@lizhongzhen11 lizhongzhen11 added the 源码 源码 label Aug 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
源码 源码
Projects
None yet
Development

No branches or pull requests

1 participant