mcpField
D
data-provider

data-provider

github.com/patternsdev开发257195 次安装28 周前更新
代码仓库

关于 data-provider

data-provider 是面向 Vue 开发者的数据提供者模式指南,介绍如何将数据获取与状态管理从界面展示中分离。它借助无渲染组件和作用域插槽,让多个组件复用数据逻辑并采用不同呈现方式。

主要功能

  1. 01封装数据获取与状态管理
  2. 02通过作用域插槽传递数据
  3. 03向子组件提供加载状态和操作
  4. 04将展示逻辑与数据逻辑分离

适用场景

  1. 01多个组件以不同方式展示同一数据
  2. 02集中管理数据获取逻辑
  3. 03替换界面组件而保留数据逻辑

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/patternsdev/skills --skill data-provider

安装后在 Claude Code 中输入/data-provider确认已加载。

详细介绍

数据提供者模式

目录

在之前的一篇文章中,我们了解到无渲染组件如何帮助将组件逻辑与其呈现方式分离。当我们需要创建可应用于不同 UI 实现的可复用逻辑时,这种做法就很有用。

无渲染组件还能让我们运用另一种有用的模式,即数据提供者模式。

何时使用

  • 多个组件需要使用相同的数据,但以不同方式展示时
  • 需要集中处理数据获取逻辑,同时避免将其与特定 UI 组件耦合时

何时不使用

  • 当组合式函数无需额外的组件层就能处理数据逻辑时(Vue 3+)
  • 只有一个组件使用数据时——使用组合式函数或内联获取会更简单
  • 数据提供者的嵌套增加了间接层,使模板更难理解时

说明

  • 创建一个数据提供者组件,其模板只包含一个带有作用域插槽属性的 <slot>
  • 将数据、加载状态和操作方法作为作用域插槽属性传递给子组件
  • 在父组件中使用 v-slot 解构来访问提供的数据
  • 让子组件专注于呈现;所有数据逻辑都由数据提供者处理

详情

数据提供者模式

数据提供者模式是一种设计模式,它通过专注于为组件提供数据和状态管理能力来补充 Vue 中的无渲染组件模式,而不关注数据如何渲染或显示。

在数据提供者模式中,数据提供者组件封装获取、管理和向子组件公开数据的逻辑。子组件随后可以使用这些数据进行自身的渲染或行为处理。

这种模式促进了关注点分离:数据提供者组件负责处理与数据相关的任务,而子组件则可以专注于展示和交互。

让我们通过一个示例来说明数据提供者模式。假设有一个简单的应用,用来显示一则有趣笑话的铺垫,然后是它的包袱。为了让示例自成一体,我们将使用本地内存数据源,而不依赖外部 API。

const jokes = [
  { id: 1, setup: "Why did the dev go broke?", punchline: "Because they used up all their cache." },
  { id: 2, setup: "Why do functions love TypeScript?", punchline: "Because it keeps their arguments in order." },
];

首先,我们将创建一个名为 DataProvider 的数据提供者组件,由它负责加载笑话。在组件的 <script> 部分,我们将从 Vue 导入 ref() 和 reactive() 函数,定义一个本地数据源,并设置 data 和 loading 响应式属性,用于记录选中的笑话和加载状态。

<script setup>
  import { ref, reactive } from "vue";

  const jokes = [
    { id: 1, setup: "Why did the dev go broke?", punchline: "Because they used up all their cache." },
    { id: 2, setup: "Why do functions love TypeScript?", punchline: "Because it keeps their arguments in order." },
  ];

  const data = reactive({
    setup: null,
    punchline: null,
  });

  const loading = ref(false);
</script>

接下来,我们可以在 DataProvider 组件中创建一个 fetchJoke() 函数,以模拟异步加载数据。

const fetchJoke = async () => {
  loading.value = true;
  try {
    await new Promise((resolve) => setTimeout(resolve, 300));
    const jokeData = jokes[Math.floor(Math.random() * jokes.length)];
    data.setup = jokeData.setup;
    data.punchline = jokeData.punchline;
  } catch (error) {
    console.error("Error loading joke:", error);
  } finally {
    loading.value = false;
  }
};

准备好获取函数后,我们可以使用 onMounted() 生命周期钩子,在组件挂载时调用它。

import { ref, reactive, onMounted } from "vue";

// ...

onMounted(() => {
  fetchJoke();
});

数据提供者组件的关键要素是,其模板只包含一个 <slot> 元素。这个插槽会使用作用域插槽向子组件提供获取到的数据和相关方法。

<template>
  <slot :data="data" :loading="loading" :fetchJoke="fetchJoke"></slot>
</template>

DataProvider 组件将 data、loading 和 fetchJoke 作为作用域插槽属性传递。这意味着,放在 DataProvider 内的任何子组件都可以访问这些属性。

现在,让我们创建一个用于展示笑话数据的 JokeCard 组件。

<template>
  <div class="joke-card">
    <p v-if="loading">Loading...</p>
    <div v-else>
      <p class="setup">{{ data.setup }}</p>
      <p class="punchline">{{ data.punchline }}</p>
    </div>
    <button @click="fetchJoke">Get Another Joke</button>
  </div>
</template>

<script setup>
  defineProps(["data", "loading", "fetchJoke"]);
</script>

JokeCard 组件是一个简单的展示组件。它接收 data、loading 和 fetchJoke 作为属性,并渲染笑话数据以及一个用于获取新笑话的按钮。

现在,我们在 App 组件中使用 DataProvider 组件,将所有内容组合起来。我们把 JokeCard 组件放在 DataProvider 内,并将作用域插槽属性传递给它:

<template>
  <DataProvider v-slot="{ data, loading, fetchJoke }">
    <JokeCard :data="data" :loading="loading" :fetchJoke="fetchJoke" />
  </DataProvider>
</template>

<script setup>
  import DataProvider from "./components/DataProvider.vue";
  import JokeCard from "./components/JokeCard.vue";
</script>

通过这种设置,DataProvider 负责所有数据获取和管理,而 JokeCard 则只专注于显示数据。这种清晰的分离让我们可以轻松换用其他展示组件,而无需改动数据获取逻辑。

以下情况尤其适合使用数据提供者模式:

  • 多个组件需要使用相同的数据,但以不同方式展示。
  • 希望集中管理数据获取逻辑,同时避免与特定 UI 组件紧密耦合。
  • 希望让组件专注于单一职责。

来源

参考资料

评论

支持 Markdown