mcpField
C
container-presentational

container-presentational

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

关于 container-presentational

container-presentational 是面向 Vue 开发者的组件架构模式指南,将数据获取与行为交给容器组件,将渲染交给展示组件。内容也说明 Vue 3 中可用 composable 实现类似分离,避免额外包装层。

主要功能

  1. 01区分容器组件与展示组件
  2. 02通过 props 传递数据和回调
  3. 03让展示组件专注渲染
  4. 04介绍 composable 替代方案

适用场景

  1. 01分离数据获取与界面渲染
  2. 02复用并测试展示组件
  3. 03在 Vue 3 中用 composable 组织逻辑

安装

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

$npx skills add https://github.com/patternsdev/skills --skill container-presentational

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

详细介绍

容器/展示组件模式

目录

2015 年,Dan Abramov 发表了一篇名为《展示组件与容器组件》的文章,改变了许多开发者对 React 组件架构的看法。他提出了一种将组件分为两类的模式:

  1. 展示组件(或哑组件):关注事物的外观。它们不负责指定数据的加载或修改方式,而是完全通过 props 接收数据和回调。
  2. 容器组件(或智能组件):关注事物的工作方式。它们向展示组件或其他容器组件提供数据和行为。

适用场景

  • 当你希望清楚地分离数据获取逻辑与 UI 渲染时,使用此模式
  • 这有助于让展示组件更易于复用和测试

说明

  • 容器组件负责处理数据获取和状态;展示组件通过 props 处理渲染
  • 在 Vue 3 中,优先使用组合式函数来实现相同的关注点分离,而不是容器组件
  • 让展示组件保持无状态——它们只通过 props 接收数据
  • 使用 useDogImages() 组合式函数模式,作为容器包装器的现代替代方案

详情

虽然这种模式主要与 React 相关联,但它的基本原则已在其他库和框架中以各种形式得到采用和改编。

Dan 的区分为 JavaScript 应用提供了一种更清晰、更具扩展性的组织方式。通过明确界定不同类型组件的职责,开发者可以确保 UI 组件(展示组件)和逻辑(容器组件)具有更好的复用性。

然而,随着 React 中 hooks 和 Vue 3 中组合式 API 的出现,展示组件与容器组件之间的明确界限开始变得模糊。Hooks 和组合式 API 让开发者能够封装并复用状态和逻辑,而不必局限于基于类的容器组件或选项式 API。即便如此,这种模式在某些时候仍然有所帮助。

假设我们想创建一个应用,获取 6 张狗狗图片,并将这些图片渲染到屏幕上。

为了遵循容器/展示组件模式,我们希望通过将这个过程分成两部分来实现关注点分离:

  1. 展示组件:关注向用户展示_什么_数据。在这个示例中,就是渲染狗狗图片列表。
  2. 容器组件:关注向用户展示数据的_方式_。在这个示例中,就是获取狗狗图片。

获取狗狗图片涉及应用逻辑,而显示图片只涉及视图。

展示组件

展示组件通过 props 接收数据。它的主要作用只是按照我们期望的方式显示接收到的数据,包括样式,_而不修改_这些数据。

渲染狗狗图片时,我们只需遍历从 API 获取的每张狗狗图片,并渲染这些图片。我们可以创建一个 DogImages 组件,通过 props 接收数据,并渲染收到的数据。

<template>
  <div>
    <div v-for="(dog, index) in dogs" :key="index">
      <img :src="dog" alt="Dog" />
    </div>
  </div>
</template>

<script setup>
  defineProps(["dogs"]);
</script>

DogImages 组件是一个展示组件。展示组件_通常_是无状态的:它们不包含自己的 Vue 状态,除非出于 UI 目的需要状态。展示组件从容器组件接收数据。

容器组件

容器组件的主要作用是将数据传递给它们所_包含_的展示组件。容器组件本身通常不会渲染其他组件,只会渲染需要使用其数据的展示组件。由于它们本身不渲染任何内容,通常也不包含任何样式。

我们需要创建一个容器组件来获取这些数据,并将数据传递给展示组件 DogImages,以便在屏幕上显示。

<template>
  <DogImages :dogs="dogs" />
</template>

<script setup>
  import { ref, onMounted } from "vue";
  import DogImages from "./DogImages.vue";

  const dogs = ref([]);

  onMounted(async () => {
    const response = await fetch(
      "https://dog.ceo/api/breed/labrador/images/random/6"
    );
    const { message } = await response.json();
    dogs.value = message;
  });
</script>

将这两个组件结合起来,就可以将应用逻辑与视图分离。

组合式函数

在很多情况下,组合式函数可以取代容器/展示模式。Composition API 的引入让开发者可以轻松地添加状态,而无需通过容器组件来提供状态。

我们可以创建一个自定义组合式函数来获取图片,并返回狗狗数组,而不是将数据获取逻辑放在容器组件中。

import { ref, onMounted } from "vue";

export function useDogImages() {
  const dogs = ref([]);

  onMounted(async () => {
    const response = await fetch(
      "https://dog.ceo/api/breed/labrador/images/random/6"
    );
    const { message } = await response.json();
    dogs.value = message;
  });

  return { dogs };
}

使用这个组合式函数后,我们不再需要用外层容器组件来获取数据。相反,我们可以直接在展示组件 DogImages 中使用这个组合式函数!

<template>
  <div>
    <div v-for="(dog, index) in dogs" :key="index">
      <img :src="dog" alt="Dog" />
    </div>
  </div>
</template>

<script setup>
  import { useDogImages } from "../composables/useDogImages";

  const { dogs } = useDogImages();
</script>

通过使用 useDogImages 组合式函数,我们仍然将应用逻辑与视图分离了。我们只使用组合式函数返回的数据,不在组件中修改这些数据。

组合式函数可以像容器/展示模式一样,轻松地将组件中的逻辑与视图分离。它省去了原本用于将展示组件包裹在容器组件中的额外层级。

来源

参考资料

评论

支持 Markdown