Skip to content

依赖注入

在父组件和子组件之间进行状态管理时,Vue 为我们提供了 props 来由上至下传递数据。Props 只能依照从父组件向子组件这个方向传递,即使子组件再向下传递也是一样。当父组件中的状态改变时,Vue 会重新渲染依赖于这些状态的组件。

alt text

大多数情况下 props 都很好用。然而,在一些大型的应用中,通常包含特别多的组件,这些组件构成一个组件树,这时 props 将变得难以维护。因为这时需要在组件树种的每个组件中都声明同样的 props。

alt text

当思考如何在大量的组件之间管理数据时,通常最佳的选择是使用应用级的状态,并使用易于维护且易于管理的状态管理工具进行管理。例如使用 Pinia 等工具创建一个可复用的状态库。我们在 状态管理 一章中对此进行了更加详细的讨论。

然而,Vue 同样提供了一种模式,避免在 Vue 应用中出现复杂的 props 透传问题。这种模式叫作依赖注入。

译注

依赖注入 Provide/Inject 的翻译遵循了 Vue 官方中文文档 的翻译。

同样可以翻译为 提供/注入模式,更贴近本篇文档的 模式 主题。

提供和注入

Vue 中的 provide() 函数允许我们在组件树中传递数据,而不需要逐级透传 props(即在每级的组件中都手动传递 props)。另一方面,在后代组件中使用 inject() 方法来访问父组件或者是祖先组件中提供的数据或方法。

alt text

我们下面通过一个简答的例子,来看一下依赖注入是如何工作的。假设我们有一个父组件叫作 App,父组件想要和子组件 ChildComponent 共享一条数据。如果不使用 prop 来传递数据,我们可以在父组件中使用 provide(),这样可以让这条数据在它所有的后代组件中可用。

vue
<template>
  <div id="app">
    <ChildComponent />
  </div>
</template>

<script setup>
  import { provide } from "vue";
  import ChildComponent from "./components/ChildComponent";

  provide("data", "Data from parent!");
</script>

接下来我们在子组件 ChildComponent 中使用 inject() 来访问这条父组件提供的数据。

vue
<template>
  <div>
    <p>{{ data }}</p>
  </div>
</template>

<script setup>
  import { inject } from "vue";

  const data = inject("data");
</script>

通过在子组件中使用 inject("data"),我们直接访问了父组件中提供的 data。我们在子组件的模板中渲染 data

在演练场中查看代码

通过提供和注入,即使组件树中有很多层级,例如我们有更多的子组件 <ChildComponent /><ChildComponent2 /><ChildComponent3 /><ChildComponent4 /><ChildComponent5 />,它们之间构成多级的组件树,我们还是会看到和上面例子中相同的结果,因为每个子组件都是另一个子组件的父组件。

vue
<template>
  <div>
    <p>{{ data }}</p>
  </div>
</template>

<script setup>
  import { inject } from "vue";
  const data = inject("data");
</script>
vue
<template>
  <ChildComponent5 />
</template>

<script setup>
  import ChildComponent5 from "./ChildComponent5";
</script>
vue
<template>
  <ChildComponent4 />
</template>

<script setup>
  import ChildComponent4 from "./ChildComponent4";
</script>
vue
<template>
  <ChildComponent3 />
</template>

<script setup>
  import ChildComponent3 from "./ChildComponent3";
</script>
vue
<template>
  <ChildComponent2 />
</template>

<script setup>
  import ChildComponent2 from "./ChildComponent2";
</script>
vue
<template>
  <div id="app">
    <ChildComponent />
  </div>
</template>

<script setup>
  import { provide } from "vue";
  import ChildComponent from "./components/ChildComponent";

  provide("data", "Data from parent!");
</script>

祖先组件 <App /> 中的数据将在 <ChildComponent5 /> 中被渲染,而这其中不需要依次在每一层组件中透传数据。让我们说谢谢提供和注入!

译注

原文就是 thanks to provide/inject!,我没说谢谢 Cheems 不错了。

在演练场中查看代码

除了由父组件提供数据之外,我们还可以将 provide() 提升到应用级别,也就是初始化 Vue 实例的位置。

javascript
import { createApp } from "vue";
import App from "./App.vue";
import "./styles.css";

const app = createApp(App);

// 应用级 provide
app.provide("data", "Data from parent!");

app.mount("#app");

应用级的 provide 在为所有组件提供数据时很好用,这个特性更多用来在创建 插件 时使用。插件通常是一段独立的逻辑,用于为整个应用添加独立的功能。

Props 和 依赖注入

什么时候该用 props,什么时候又该用依赖注入模式呢?它们二者都各有优缺点。

Props

  • 优点:使用一种很清晰的传值方式,将数据传递给下级的组件。

  • 缺点:如果组件树很复杂,逐层透传 props 会特别麻烦。

依赖注入

  • 优点:子组件可以直接访问祖先组件提供的数据,无需逐级透传。

  • 缺点:当程序出现 bug 时,依赖注入引起的问题更不容易调试。当大型应用中包含多个 provide 时,这个缺陷会更加明显。

依赖注入模式是在应用层面保存数据的最佳选择,例如主题、本地化语言设置、用户认证信息等。这些种类的数据可以通过依赖注入进行更好的管理,因为应用中的任何组件都可能在任何时间需要对它们进行访问。

另一方面,当数据只需要在一组特定的组件中使用时,props 此时是最佳选择。

扩展阅读

依赖注入 | Vue 文档

评论区
评论区空空如也
发送评论
名字
0 / 20
邮箱
0 / 100
评论内容
0 / 140
由于是非实名评论,所以不提供删除功能。如果你需要删除你发送的评论,或者是其他人的评论对你造成了困扰,请 发邮件给我 。同时评论区会使用 AI + 人工的方式进行审核,以达到合规要求。

© thebestxt.cc
辽ICP备16009524号-8
本站所有文章版权所有,转载请注明出处