Vue3 关于 provide、inject 的用法

前言: 在前端项目中牵扯的最多的莫过于组件之间的传值了,除了最最常用的 propsemit,其实在 Vue 中还额外提供了另外几种方法。今天分享一种组件之间通信的方法。


一. 场景再现

  1. 先别着急考虑标题这个 api 的含义。在这里我先动手写一个比较常见的场景。
    所对应的组件内部代码比较简单,这里我就不展示了,逻辑上就是 这三个组件层层引用。
    图片[1] - Vue3 关于 provide、inject 的用法 - MaxSSL
    所对应的页面效果如下:
    图片[2] - Vue3 关于 provide、inject 的用法 - MaxSSL

  2. 如上图,这是一个在项目中很常见的一个场景,三层嵌套的组件。(其实还有深层次的嵌套,目前我们拿三层嵌套举例足矣)

  3. ok,你现在的需求是:在爷爷组件内需要提供一个字符串数据 “韩振方” 去提供给 儿子组件使用。

  4. 聪明的你肯定想到了 props,废话不多说,我们直接上手。

二. 传递 Props

  1. “我以为多高深呢,这不就是数据父传子的场景吗?我直接传递 props 去完成这个需求。”

  2. 于是我会在 GrandFather.vue写下这样一段代码
    图片[3] - Vue3 关于 provide、inject 的用法 - MaxSSL

  3. 接下来就该去 Father.vue 组件去接收这个数据了。于是我们在 Father.vue 组件定义了 props 去接收这个值。
    图片[4] - Vue3 关于 provide、inject 的用法 - MaxSSL
    我们看一眼页面
    图片[5] - Vue3 关于 provide、inject 的用法 - MaxSSL
    没什么问题,爸爸组件已经收到了。但是别忘了我们任务还没完成呢,我们的需求是给儿子组件使用,

  4. 于是我们又赶紧接着往下传递。
    图片[6] - Vue3 关于 provide、inject 的用法 - MaxSSL

  5. 所以现在我们的 Children.vue 组件的样子就变成这个样子。
    图片[7] - Vue3 关于 provide、inject 的用法 - MaxSSL
    页面效果如下:
    图片[8] - Vue3 关于 provide、inject 的用法 - MaxSSL
    最终我们的 儿子组件 也确实拿到了。

  6. 写到这里你发现了一些不太对劲的地方吗?

  7. 其实我们的爸爸组件是完全不需要知道这些属性的,它仅仅只是充当了一个传话筒。如果这个组件单纯是这一个使用场景还好,但是一旦我们想要在第二个地方复用爸爸组件的时候,我们会发现问题就来了。我们必须给这个爸爸组件提供一个叫做 message1props,但是实际上这个 message1 并不是一个爸爸组件内部自己使用的一个属性。

  8. 写到这里你发现了,仅仅只多传递了一层,就导致组件的复用性变得很差。这还是仅仅只嵌套了三层的场景,一旦到了第四层,你会发现事情逐渐开始变得棘手起来了,好像 props 并不是一个好的选择了。

  9. 想到这里你会开始思考,有没有更好的解决方法呢?你别说,还真有,那就是我们今天的主角,provideinject

三. provide 和 inject

  1. 首先不要死记硬背 api 的名字,作者起名字肯定都是有原因的。在很多情况下我们通过先看这两个单词的意思。
    图片[9] - Vue3 关于 provide、inject 的用法 - MaxSSL
    图片[10] - Vue3 关于 provide、inject 的用法 - MaxSSL

  2. 单从这两个单词的含义就大概能猜出个大概的意思,一个是提供某个值,另一个是去注册接收这个值。

  3. 那么问题就引出来了,我们怎么正确的使用这两个 api 呢?其实很简单,让我们回到爷爷组件,还原他最初的模样。
    图片[11] - Vue3 关于 provide、inject 的用法 - MaxSSL

  4. 你做的仅仅只需要两步:
    图片[12] - Vue3 关于 provide、inject 的用法 - MaxSSL
    或许你会惊讶,就这样就行了?我明确告诉你,是的,这样就行了。

  5. 接下来最后一步,去儿子组件接收使用就大功告成了。
    图片[13] - Vue3 关于 provide、inject 的用法 - MaxSSL
    我们看一下页面效果:
    图片[14] - Vue3 关于 provide、inject 的用法 - MaxSSL

  6. 不仅仅数据成功拿到了,而且关键的是我们的爸爸组件是干干净净的,丝毫不影响其他地方对它的引用。
    图片[15] - Vue3 关于 provide、inject 的用法 - MaxSSL

  7. 我们再回过头讲解 provide 的用法。provide 接受两个参数。第一个参数需要是一个独一无二的标识(不允许和组件内部的变量重名),第二个参数就是准备传递的值。
    你也可以这样理解,现在爷爷组件拿着一个喇叭在喊:“谁要‘韩振方’,谁要‘韩振方’,价格便宜,仅仅需要一个‘message’”。

  8. 这时候儿子组件听到了这个消息,大喊:“我要我要!!”于是它就赶紧 inject 了一个 “message”。
    图片[16] - Vue3 关于 provide、inject 的用法 - MaxSSL
    注意: 你用于接受的变量名字是随便起的,不需要你和前面保持一致。
    图片[17] - Vue3 关于 provide、inject 的用法 - MaxSSL

  9. 爸爸组件丝毫不想要,所以它就压根不需要 inject

  10. 并且 inject 还可以允许你有个兜底的行为。什么意思” />

  11. 我们测试一下,我们首先取消了爷爷组件provide 行为。
    图片[18] - Vue3 关于 provide、inject 的用法 - MaxSSL
    可以看到,页面正确的显示了我们的兜底数据。
    图片[19] - Vue3 关于 provide、inject 的用法 - MaxSSL

三. provide 的进阶用法

  1. provide 的作用远远不止提供字符串类型数据而已,我们在爷爷组件声明一个响应式的数据试试。
    图片[20] - Vue3 关于 provide、inject 的用法 - MaxSSL

  2. 让我们看一下儿子组件是否可以正确的响应。
    图片[21] - Vue3 关于 provide、inject 的用法 - MaxSSL
    可以看到,确实是可以的。

  3. 现在儿子组件长大了,它说我自己也想控制数字的增长,可以吗?爷爷组件是很宠孙子的,于是又提供了一个方法给孙子使用。
    图片[22] - Vue3 关于 provide、inject 的用法 - MaxSSL

  4. 儿子组件真的可以自己控制吗?孩子真的长大了吗?
    图片[23] - Vue3 关于 provide、inject 的用法 - MaxSSL
    我们测试一下:
    图片[24] - Vue3 关于 provide、inject 的用法 - MaxSSL
    可以看到儿子组件确实是长大了(指成功 inject爷爷组件 provide 的函数)

  5. 千万不要转头就忘,第二个参数是我们的兜底行为。如果爷爷没提供函数,我就自己使用一个没有任何行为的箭头函数。仅此而已。
    图片[25] - Vue3 关于 provide、inject 的用法 - MaxSSL

四. 源码

爷爷组件代码

// 这是爷爷组件import { ref } from "vue";import { provide } from "vue";import Father from "./Father.vue";const count = ref(0);function add() {count.value = count.value + 1;}provide("message", count);provide("messageAdd", add); //我把 add 也同时提供给儿子组件爷爷组件

父亲组件代码

// 这是父亲组件import Children from "./Children.vue";爸爸组件

儿子组件代码

// 这是儿子组件import { inject } from "vue";const suibian = inject("message", "假如爷爷没提供没有的话就用我");const add = inject("messageAdd", () => {});儿子组件{{ suibian }}

五. 思考题

如果我现在爷爷组件父亲组件同时提供了一个相同的关键词的值,儿子组件最后会使用谁的呢?

GrandFather.vue: => provide("message","爷爷组件提供的");
Father.vue: =>provide("message","父亲组件提供的")

Children.vue:=> inject("message","我使用谁的?")

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享