南妮!vue引用组件时总报错,必须得查这查那的源码
背景
原则上,为了便于维护和统一,我们会把可能在多个地方使用的功能做成一个组件。
而接手项目的时候,也尽量使用别人已有的组件。
这不,最近刚接手了个项目,引用别人的组件时,有些是可以使用的,但过些时间,发现就不能使用了,有的不能使用,直接报错。
本来好的,突然坏了这种就很搞事情了,要是没发现,演示是被老板看到岂不直接死翘翘?
问题现象
然后报错信息类似 [Vue warn]: Property or method "valueList" is not defined on the instance but referenced during render.
。
然后组件无法按预取工作,渲染不正常,功能无法使用。
问题排查
- 检查组件是否可使用
反正组件在自己的页面运行不正常,如果知道别人哪里有使用这个组件的情况下,先去看看这个组件在别人的页面上是不是能正常使用。
别人的页面能正常使用。
- 确定使用方式
那么看看是不是自己的使用方式不对。这时候就得看组件的 API 文档,这个当然一般都没有,所以就只能看源码了。源码先看入参部分,好家伙,props 该传的都传了。
搜索一下报错的东西,valueList 有匹配结果 inject:['valueList']
,这是什么鬼?看起来这像是要注入一个参数,而我没有注入。
百度一下 vue inject
由于是 vue 项目所以需要添加关键字作为限定。
在父组件只要声明了provide,在其子组件,孙组件,曾孙组件等能形成上下游关系的组件中交互,无论多深都能通过inject来访问provider中的数据。
看起来在这个组件需要依赖 valueList 这个数据,可能我没有在我的页面里使用 provide
。
解决问题
那么问题来了, valueList 数组是什么?我该构造怎样的数据给它?
好吧,这时候就得查找别人是怎么引用这个组件的,然后根据 inject
的使用方式,需要找到引用这个组件的父级里找 provide
参数在哪声明的,需要看看构造这个参数的地方是怎样构造的。
那吧,上一层没有,再上一层……
也可以直接在代码中那家关键字 valueList
找到附近有 provide
即大概率确认。
现在,在一个上上上级 index.vue 中找到了以下代码片段:
provide(){
return {
valueList:() => this.valueList
}
},
看起来还得再找 this.valueList 是什么东西……
知道了 valueList
是怎么构造的,这下还得思考,在自己的引用这个组件的地方,能不能构造出现这样的数据,例如这些数据可能由其他参数产生,但这个参数你所在的页面不一定能拿到。
思考问题根源
通过上面这些历程,不禁让人沉思,用个组件这么麻烦?不应该引用后传入必要的参数就好了嘛?像 antd / element-ui 这些 ui 组件库一样。
为什么看了组件本身的源码不行,还得看组件上上上层的源码?
这相当于定义了一个未知作用域的未知位置的不易追踪的“全局”变量,与 单向数据流
、状态可管理
截然相反。
解决问题根源
通过上面这些历程,我不认为这样的 inject 使用方式是一种优雅的使用方式。于是百度 不推荐 inject
类似的关键字,希望能找到一些大佬“喊话”,然后向人说明这样的搞法不行,这样搞得我用组件的人很难受。
果然,在官网上就有醒目的警告注明:
provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
另外在很多第三方文章中也有:
官网不建议在应用中直接使用该办法,理由很直接:他怕你"管不好"
设计项目,通常追求有清晰的数据流向和合理的组件层级关系便于调试和维护,然而这对选项支持任意层级都能访问,导致数据追踪比较困难。不知道那一层级声明了provide又或是哪些层级使用了inject。造成比较大的维护成本。因此,除组件库或高阶插件外,Vue建议用Vuex解决或其他办法处理。
果然不出所料,找到各种文献,就可能借他人之口让写组件的人处理一下这些问题了。
后记
像这种不太负责的 inject 实现已经贯穿了整个项目的五心六腑,要改的地方可能很多。在这种情况下,如何愿意改和如何改又是一门学问了。