在 React 中使用 Storybook,构建强大的自定义 UI 组件
虽然像React这样的基于组件的UI库简化了web开发,但它们也引入了测试和调试等新的复杂性。
React组件是为了支持多个用例而构建的,并且通常是相互依赖的,这意味着如果你走错了弯路,你就有可能破坏应用程序。
Storybook使开发人员能够使用独立的构建块独立地构建UI组件。使用Storybook,您可以使用您最喜欢的框架快速创建UI组件,同时还提供一个整洁的接口来处理每个组件。
Storybook是UI组件的开发环境,它允许您在主应用程序之外的环境中创建和展示组件。这允许您一次只处理一个模块,开发整个ui,而不需要复杂的开发堆栈。
Storybook还允许您记录、重用和测试用户界面组件。除此之外,它使构建web应用程序更快、更高效。
该工具有一个广泛的插件生态系统,可以帮助扩展和调整您的应用程序。此外,它还集成了最流行的JavaScript框架,如React、Vue甚至Ruby。
你应该在React中使用Storybook吗?
与React一样,Storybook是记录UI组件和设计系统的一种引人注目的可视化方式。
除此之外,它还是呈现技术文档和演示实现细节的优秀工具。它还有助于在用户有机会与新配置进行交互之前测试它们。
但这还不是全部。对于想要构建更好组件的开发者来说,Storybook有很多好处:
简化组件构建:Storybook创建独立运行的“故事”或小组件,然后可以将其添加到应用程序中。
防止重复工作:有时,开发人员创建一个组件,却发现代码库中已经有类似的东西了。有了Storybook,每个组件都被记录下来,其他人也可以访问,从而避免了重复工作。
创建一个活的风格指南:Storybook的代码模板是你可以使用和开发的活的代码块,确保开发人员在构建一个web应用程序时不会使用模型或类似的容易出错的模板。
隔离构建组件:隔离开发可确保您只关注正在构建的组件。你不需要考虑应用的其他部分,因为你在Storybook中构建的每个组件都在自己的文件夹中,那里有用于实现和测试的文件。
构建第一个 Storybook 组件
Storybook使用组件驱动开发(CDD)方法来创建UI组件。按照这种方法,您可以模块化地构建,从基本组件开始,逐步将它们组合成复杂的屏幕和应用程序。
此外,组件使您能够使用可互换的部分并在不影响应用程序的业务逻辑的情况下交换它们,从而允许您将组件拆开,并根据需要将它们重新组合到不同的ui中。
既然您已经了解了组件驱动的开发,并且已经看到了Storybook的好处,那么让我们开始吧。如果你按照这个食谱做,我相信你会得到美味的配料。
准备
这是你开始使用Storybook时需要做的:
基本了解React、JavaScript和TypeScript
一个代码编辑器,比如Visual Studio code
Node.js安装在您的机器上
NPM安装在你的机器上
如何安装 Storybook
关于Storybook和React的一大亮点便是它们能够很好地结合在一起。事实上,Storybook会检测到你正在使用Create React App,并为你安装依赖项。这是有帮助的,特别是如果你是一个初学者。
在本教程中,我们使用的是Next.js。当然,你可以使用Vue、Angular和其他框架,但为了简单起见,我们将使用React。
1. 使用 Next.js 创建 React APP
在我们开始Storybook的冒险之前,我们首先需要创建一个正在运行的Next.js应用程序,以便我们可以在其中安装Storybook。
如果你还没有一个React应用来添加Storybook,你可以先通过初始化Next.js应用来创建一个。在你的终端中,运行以下命令:
npx create-next-app <your-app-name>
上面的命令将在运行它的目录中生成一个新的Next.js应用程序,并且在运行提示时将具有您提供的相同名称(
例如,如果你将它命名为nextjs-storybook-example,你应该在你的终端中运行以下命令来导航到它:
cd nextjs-storybook-example
2. 在React应用中初始化Storybook
现在我们已经启动并运行了React应用程序,我们需要安装并设置Storybook的本地实例。
进入应用程序的目录后,运行以下命令安装Storybook:
npx sb init
这将快速建立一个工作的Storybook实例所需的样板。Npx是自[email protected]以来安装在npm旁边的npm包运行器。
一旦我们建立了Storybook实例,让我们确保所有必需的依赖项都通过运行来安装:
npm install
3. 在本地运行 Storybook
现在让我们运行Storybook实例:
npm run storybook
一旦命令成功运行,Storybook应该开始在http://localhost:port/上运行:
4. 为Storybook创建第一个组件
让我们创建一个横幅组件来添加到应用程序中。要做到这一点,让我们打开我们的项目文件夹,进入我们的代码编辑器,我们可以看到/src
目录和/stories
文件夹,这是运行sb init
时自动生成的。
在这个文件夹中创建一个名为Banner.jsx
的文件。
在这个文件中,让我们添加以下代码:
/** @jsxImportSource @emotion/react */
import React from "react";
export default function Banner({ variant = "info", children }) {
return <aside> {children} </aside>;
}
Banner.propTypes = {
variant: "info" | "congrats" | "documentation" | "danger",
};
PropTypes
或TypeScript
类型被Storybook
用来自动生成故事中的一些文档。
现在我们有了无样式的组件,让我们用一些CSS给它增添一些风味。
一个CSS对象可以用来动态地在不同的变量上应用不同的样式。例如,Emotion是一个支持用JavaScript编写CSS对象的库。我们将在本教程中使用它来帮助我们设计组件。
你可以在Node中输入以下命令来安装Emotion:
npm install @emotion/react
为了让Emotion能够在JS中正确处理CSS,我们应该在Banner的顶部添加以下一行。jsx文件:
/** @jsxImportSource @emotion/react */
下面是一个如何根据道具的值将不同的样式应用到React组件的例子。这将使我们的banner组件能够根据它的状态改变样式。
/** @jsxImportSource @emotion/react */
import React from "react";
export default function Banner({ variant = "info", children }) {
const beforeStyles = {
width: 35,
height: 35,
display: "inline-flex",
justifyContent: "center",
position: "absolute",
left: "-1.2rem",
borderRadius: "50%",
alignItems: "center",
top: "-0.8rem",
};
const variantStyles = {
info: {
borderLeft: "4px solid #b4aaff",
backgroundColor: "rgba(224, 226, 255, 0.5)",
color: "#2a2135",
"&:before": {
content: '"🔑"',
backgroundColor: "#b4aaff",
...beforeStyles,
},
},
danger: {
borderLeft: "4px solid #ff7828",
backgroundColor: "rgb(253, 236, 234)",
"&:before": {
content: '"⚠️"',
backgroundColor: "#ff7828",
...beforeStyles,
},
},
congrats: {
borderLeft: "4px solid #72bc23",
backgroundColor: "rgb(249, 253, 234)",
"&:before": {
content: '"🎉"',
backgroundColor: "#72bc23",
...beforeStyles,
},
},
documentation: {
borderLeft: "4px solid #44a9ba",
backgroundColor: "rgb(234, 248, 253);",
"&:before": {
content: '"📚"',
backgroundColor: "#44a9ba",
...beforeStyles,
},
},
};
return (
<aside
css={{
margin: "1.5rem auto",
borderRadius: "0px 10px 10px 0px",
padding: "0.8em 1em",
lineHeight: "1.2",
textAlign: "center",
position: "relative",
clear: "both",
maxWidth: "500px",
...variantStyles[variant],
}}
s
>
{children} {" "}
</aside>
);
}
Banner.propTypes = {
variant: "info" | "congrats" | "documentation" | "danger",
};
这将改变banner组件的样式:
成为这样:
variantStyles对象具有针对Banner支持的每个变体的特定样式的键。也就是说,如果变量道具的值是“documentation”,那么我们将应用variantStyles[documentation]中包含的样式。
下面是一个variantStyle对象的例子:
{
borderLeft: "4px solid #44a9ba",
backgroundColor: "rgb(234, 248, 253);",
"&:before": {
content: '"📚"',
backgroundColor: "#44a9ba",
},
},
5. 创建第一个 Story
在将一个文件添加到/stories
文件夹之后,我们需要添加一个相关的故事文件来查看Storybook中的组件。
这个新文件应该被添加到命名为Banner.stories.jsx
的stories
文件夹中,以便您的默认Storybook配置能够充分地检测到它。
在这个例子中,我创建了Banner.stories.jsx
,并导入了在上一步中创建的Banner组件。
我还为默认导出添加了“info”、“congratulations”、“documentation”和“danger”等元数据,因为Storybook使用这些信息列出故事,并提供关于特定部分的额外细节。
Banner.stories.jsx
中,我还定义了一些常量来渲染Banner与不同的道具。Storybook会自动将它们转换成与常量同名的故事。
import React from "react";
import Banner from "./Banner";
export default { title: "Example/Banner", component: Banner };
export const Info = () => (
<Banner variant="info">
{" "}
{" "}
<p>
{" "}
This is an example of an info banner to display important
information. {" "}
</p>{" "}
{" "}
</Banner>
);
export const Danger = () => (
<Banner variant="danger">
{" "}
<p>This is an example of a danger banner to display warnings.</p> {" "}
</Banner>
);
export const Congrats = () => (
<Banner variant="congrats">
{" "}
<p> This is an example a congrats banner to celebrate a win!</p> {" "}
</Banner>
);
export const Documentation = () => (
<Banner variant="documentation">
{" "}
{" "}
<p>
{" "}
This is an example a documentation banner to highlight relevant reading
materials and documentation.{" "}
</p>{" "}
{" "}
</Banner>
);
6. 在Storybook中查看story
让我们重新查看Storybook实例,并导航到我们刚刚创建的组件。
在我的例子中,我从侧边导航栏中选择了Banner,然后点击了docs,这就指向了http://localhost:port/?path=/docs/example-banner--info。
这个特定的文档视图包含了我们在前面步骤中定义的所有各种Banner故事的摘要,并强调了它们的视觉差异。它还包括一个按钮“显示代码”,可以切换到查看JSX并生成特定的元素。
7. 在 React APP 中使用 story
要在React应用中使用这个故事,我们可以导入创建好的Banner。在你的Next.js安装中,把jsx文件放到index.js文件夹中。
import Banner from "../stories/Banner.jsx";
然后,我们可以像往常一样使用这个组件,用相应的道具和子HTML编写一个它的实例,如下所示:
<Banner variant="info">
<p>This is an example of how we can use our components from Storybook in a NextJS application. JSX components that are defined in Storybook can be imported/exported like regular JSX components. If you need to import components from Storybook in external applications then you should explore publishing a NPM package that contains the relevant components.</p>
</Banner>
添加 Banner.jsx。在我们的Next.js的index.js的头部上方的jsx将呈现一个页面看起来像这样:
上面的例子展示了当故事位于同一个项目中时,如何从Storybook导入组件。
然而,如果你需要从外部应用程序的Storybook中导入它们,你应该尝试发布一个包含Storybook组件导出的npm包。
这将使您能够跨项目导入它们,但为了简单起见,我们在单个项目中构建了所有内容。
现在我们已经有了一个可以运行的样式组件,让我们直接进入Storybook的特性,它允许你构建漂亮的ui。