Vue 3 进阶用法:Provide / Inject 机制

一、属性下钻

属性可用于父组件向子组件传递参数,但仅限于相邻父子组件。如果一个组件要给它的子组件的子组件(即孙组件)传递参数,不得不拆成两个步骤:先传给它的儿子,再由儿子传给孙子。

Vue 3 进阶用法:Provide / Inject 机制

祖孙三代之间的属性透传

尽管可以实现目的,但是中间层组件需要定义自身用不到的属性。如果嵌套层级更深,需要传递的属性更多,可以想象,这条链路的每个中间层组件都会变得不幸。这种为了透传而声明属性造成的不幸,Vue 叫它属性下钻(Prop Drilling)。

二、Provide 和 Inject

为了解决属性下钻的问题,Vue 提供了 Provide/Inject 解决方案。这个方案定义了两个角色:ProviderInjector,Provider 是数据的提供方,Injector 是数据的消费方。

Provider 通过 provide(key, data) 把数据存放在特定区域,Injector 通过 inject(key) 从特定区域获取数据。其中的 key 用于区分不同用途的数据。

Vue 3 进阶用法:Provide / Inject 机制

数据的提供和获取

这套机制跟智能取餐柜有些类似。送餐员是食物(数据)的 Provider,你是食物的 Injector,而 key 是取餐柜号。送餐员通过 provide(key, food) 把食物放到特定柜子,你通过 inject(key) 从正确的柜子取走食物并消费它。

和取餐柜不同的是,一个 Provider 可以对应多个 Injector。即父组件提供一条数据后,可以被子子孙孙组件反复消费。

provide() 函数的两个参数,第一个参数叫注入键(injection key),类型可以是字符串或 Symbol。第二个参数是注入的数据,可以是任意类型,包括响应式数据。

Vue 3 进阶用法:Provide / Inject 机制

使用 provide 和 inject 传递数据

渲染效果:

Vue 3 进阶用法:Provide / Inject 机制

使用 provide 和 inject 的渲染结果

三、同名覆盖

在一个层级较深的组件树中,如果出现多个 Provider 组件,且提供的 key 是一样的,最终 Injector 取到的数据是怎样的?

Injector 永远获取离它最近的祖先组件提供的数据,再往上的数据会被同名覆盖。用代码验证一下:

Vue 3 进阶用法:Provide / Inject 机制

同名覆盖

渲染效果:

Vue 3 进阶用法:Provide / Inject 机制

同名覆盖的渲染结果

如果你在开发一个很大的应用,为了防止同名覆盖,可以在 provide() 中使用 Symbol 类型取代字符串。

四、最顶级的 Provider

在 Vue 3 中,最顶级的 Provider 是 app。通过 app.provide(key, value) 提供数据。数据的消费方法没有什么不同。

Vue 3 进阶用法:Provide / Inject 机制

顶级 Provider

Vue 3 进阶用法:Provide / Inject 机制

顶级 Provider 的渲染结果

五、Inject 默认值

如果子组件通过 inject(key) 消费了一个 key,但是所有的上级组件都没提供数据,会让 Vue 恼火,并发出警告信息。

Vue 3 进阶用法:Provide / Inject 机制

上游没有提供数据,但下游用了

Vue 3 进阶用法:Provide / Inject 机制

没有注入数据的渲染结果

为了平息 Vue 的警告信息,可以在子组件使用 inject() 时,传入第二个参数当作默认值。

Vue 3 进阶用法:Provide / Inject 机制

使用默认值

这样,当所有上级都不提供数据时,子组件就会启用默认值。

Vue 3 进阶用法:Provide / Inject 机制

正常显示默认值

有的时候,默认值需要调用工厂函数计算才能获得。此时,函数本身不是默认值,函数的返回值才是默认值,需要将 inject() 第三个参数设为 true,表明第二个参数的特殊作用。

Vue 3 进阶用法:Provide / Inject 机制

标记默认的工厂函数

六、处理响应式数据

如果提供的数据是响应式数据,提议把响应式数据变更数据的方法放在一个地方,打包一并提供给下游。谁声明谁治理,这样职责比较清晰。

Vue 3 进阶用法:Provide / Inject 机制

响应式数据的声明和变更在一个地方

渲染结果:

Vue 3 进阶用法:Provide / Inject 机制

响应式数据的渲染结果

对于某些重大数据,如果上游组件不希望下游组件改动,可以先用 readonly() 方法保护好,然后再打包发送给下游。

Vue 3 进阶用法:Provide / Inject 机制

设定为只读数据

下游修改只读数据时,Vue 不仅会阻止操作,还会发出警告:

Vue 3 进阶用法:Provide / Inject 机制

修改只读数据时的警告信息

参考资料

  • Provide / Inject,https://vuejs.org/guide/components/provide-inject.html

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容