返回Storybook 简介
章节
  • 开始
  • 简单组件
  • 复合组件
  • 数据
  • 结论
  • 贡献

构建一个简单组件

隔离构建一个简单组件
此社区翻译尚未更新至最新版本的 Storybook。请帮助我们更新它,将英语指南中的更改应用于此翻译。 欢迎提交 Pull Request.

我们将遵循组件驱动开发 (CDD) 方法论构建我们的 UI。这是一个从“自下而上”构建 UI 的过程,从组件开始,到屏幕结束。CDD 帮助您在构建 UI 时应对日益增长的复杂性。

任务

Task component in three states

`Task` 是我们应用中的核心组件。每个任务的显示方式略有不同,具体取决于它所处的状态。我们显示一个已选中(或未选中)的复选框、一些关于任务的信息和一个“置顶”按钮,允许我们将任务在列表中上下移动。综上所述,我们将需要以下 props

  • `title` – 描述任务的字符串
  • `state` - 任务当前在哪个列表中,以及是否已选中?

当我们开始构建 `Task` 时,我们首先编写与上面草绘的不同类型任务相对应的测试状态。然后我们使用 Storybook,使用模拟数据隔离构建组件。我们将随着进行“视觉测试”组件在每种状态下的外观。

此过程类似于测试驱动开发 (TDD),我们可以称之为“视觉 TDD”。

设置

让我们打开 `.storybook/main.js` 并查看一下

复制
.storybook/main.js
module.exports = {
  stories: ['../components/**/*.stories.?(ts|tsx|js|jsx)'],
  addons: [
    '@storybook/addon-ondevice-controls',
    '@storybook/addon-ondevice-actions',
  ],
};

如果您查看 `stories` 属性,您将看到 Storybook 正在 `components` 文件夹中查找 stories。

在 React Native 的 Storybook 中,由于 Metro bundler 当前的限制,我们依赖于 `main.js` 中的配置来生成一个名为 `storybook.requires` 的文件,该文件用于加载我们项目中的所有 stories 和 addons。当您运行 `yarn storybook` 启动 Storybook 时,此文件会自动生成。

💡 您还可以通过运行 `yarn storybook-generate` 手动生成 `storybook.requires` 文件。但是,除非您看到某个 story 未被加载,或者注意到 `main.js` 配置中的更改未反映在您的 Storybook 中,否则您无需重新创建此文件。要了解有关 `storybook.requires` 文件如何生成的更多信息,您可以查看 `metro.config.js` 文件中的 `withStorybook` 函数。

现在让我们创建 task 组件及其附带的 story 文件:`components/Task.jsx` 和 `components/Task.stories.jsx`。

我们将从 `Task` 的基本实现开始,只需接收我们知道需要的属性以及您可以对任务执行的两个操作(在列表之间移动它)

复制
components/Task.jsx
import { StyleSheet, TextInput, View } from 'react-native';
import { styles } from './styles';

export const Task = ({
  task: { id, title, state },
  onArchiveTask,
  onPinTask,
}) => {
  return (
    <View style={styles.listItem}>
      <TextInput value={title} editable={false} />
    </View>
  );
};

现在添加 story 文件

复制
components/Task.stories.jsx
import { Task } from './Task';

export default {
  title: 'Task',
  component: Task,
  argTypes: {
    onPinTask: { action: 'onPinTask' },
    onArchiveTask: { action: 'onArchiveTask' },
  },
};

export const Default = {
  args: {
    task: {
      id: '1',
      title: 'Test Task',
      state: 'TASK_INBOX',
    },
  },
};

export const Pinned = {
  args: { task: { ...Default.args.task, state: 'TASK_PINNED' } },
};

export const Archived = {
  args: { task: { ...Default.args.task, state: 'TASK_ARCHIVED' } },
};

在我们的 stories 文件中,我们使用一种名为组件 Story Format (CSF) 的语法。此语法使编写 stories 更容易,并且受到最新版本 Storybook 的支持。

Storybook 中有两个基本的组织级别:组件及其子 stories。将每个 story 视为组件的一种排列。您可以根据需要为每个组件设置任意数量的 stories。

  • 组件
    • Story
    • Story
    • Story

为了告诉 Storybook 我们正在记录的组件,我们创建一个 default export,其中包含

  • `component` -- 组件本身
  • `title` -- 如何在 Storybook 应用的侧边栏中引用该组件
  • `argTypes` -- 允许我们指定 args 的类型,在这里我们使用它来定义操作,这些操作将在每次发生交互时记录日志

为了定义我们的 stories,我们导出一个带有 `args` 属性的对象。参数或 args 简称,允许我们使用 controls addon 实时编辑组件,而无需重启 Storybook。一旦 args 值发生更改,组件也会随之更改。

在创建 story 时,我们使用基本的 `task` arg 来构建组件期望的任务形状。通常根据实际数据的外观建模。同样,导出此形状将使我们能够在以后的 stories 中重用它,正如我们将看到的。

现在我们已经设置了基础知识,让我们重新运行 `yarn storybook` 并查看我们的更改。如果您已经运行了 Storybook,您也可以运行 `yarn storybook-generate` 以重新生成 `storybook.requires` 文件。

您应该看到如下所示的 UI: a gif showing the task component in storybook

您可以使用屏幕底部的菜单打开导航菜单,然后点击以在 stories 之间切换。然后您可以点击离开或向下拉动以关闭菜单。您可以通过按底部栏最右侧的图标找到 addons。

构建状态

现在我们可以开始构建我们的组件以匹配设计。

该组件目前仍然很基础。首先编写实现设计效果的代码,而无需过多细节

复制
components/Task.jsx
import { MaterialIcons } from '@expo/vector-icons';
import { StyleSheet, TextInput, TouchableOpacity, View } from 'react-native';
import { styles } from './styles';

export const Task = ({
  task: { id, title, state },
  onArchiveTask,
  onPinTask,
}) => {
  return (
    <View style={styles.listItem}>
      <TouchableOpacity onPress={() => onArchiveTask(id)}>
        {state !== "TASK_ARCHIVED" ? (
          <MaterialIcons
            name="check-box-outline-blank"
            size={24}
            color="#26c6da"
          />
        ) : (
          <MaterialIcons name="check-box" size={24} color="#26c6da" />
        )}
      </TouchableOpacity>
      <TextInput
        placeholder="Input Title"
        value={title}
        editable={false}
        style={
          state === "TASK_ARCHIVED"
            ? styles.listItemInputTaskArchived
            : styles.listItemInputTask
        }
      />
      <TouchableOpacity onPress={() => onPinTask(id)}>
        <MaterialIcons
          name="star"
          size={24}
          color={state !== "TASK_PINNED" ? "#eee" : "#26c6da"}
        />
      </TouchableOpacity>
    </View>
  );
};

完成后,它应该看起来像这样

a gif showing the task component in storybook

组件已构建!

我们现在已经成功构建了一个组件,而无需服务器或运行整个应用程序。下一步是以类似的方式逐个构建剩余的 Taskbox 组件。

正如您所看到的,开始隔离构建组件既简单又快速。我们可以期望生产出更高质量、更少错误、更精细的 UI,因为可以深入挖掘并测试每种可能的状态。

💡 别忘了用 git 提交您的更改!
这个免费指南对您有帮助吗?发推文以示赞赏并帮助其他开发者找到它。
下一章
复合组件
用更简单的组件组装一个复合组件
✍️ 在 GitHub 上编辑 – 欢迎提交 PR!
加入社区
6,721开发者计数中
为什么为什么 Storybook组件驱动的 UI
开源软件
Storybook - Storybook 中文

特别感谢 Netlify CircleCI