Post

Storybook을 사용해보자(1) - 예제 뜯어보기

📌시작하며

프론트엔드 개발자는 "타 직군과 커뮤니케이션🤝 할 상황이 굉장히 많다"라는 건 아마 모두가 인정하는 사실일 것이다. 하나의 프로덕트를 위해 디자이너와 백엔드 개발자는 물론, 서비스 기획, 프로젝트 매니저 등 정말 많은 사람과 함께 달려가는거다!

(개인적으로 이 과정이 개발자가 가진 매력 중 하나가 아닐 까 생각한다. 마치 소년만화의 주인공이 된 기분!😎)

또한, 개발자는 같은 직군의 개발자와도 협력해 작업하기 때문에 ‘여러명이 작업해도 한 명이 작업한 것과 같은’ 통일성을 갖추는 것도 제품의 통일성과 퀄리티를 높이는 데 중요한 역할을 할 것이다.

이를 위해 문서화, 컴포넌트 관리가 필요해졌고 이를 편리하게 해주는 도구가 Storybook이다.

✅스토리북이란?

스토리북 공식 홈페이지는 스스로를 이렇게 설명한다.

스토리북은 UI 컴포넌트와 페이지를 독립적으로 구축하기 위한 프론트엔드 워크샵입니다. 수천 개의 팀이 UI 개발, 테스트 및 문서화를 위해 사용하고 있습니다. 오픈 소스이며 무료입니다.

계속해서 살펴보면,

  1. Storybook은 UI를 격리된 환경에서 구축할 수 있는 환경을 제공한다. 이를 통해 전체 앱을 실행할 필요 없이 달성하기 어려운 상태와 경계 조건을 확인할 수 있다.
  2. Stories는 UI 컴포넌트의 “올바른 상태”를 포착하는 실용적인 방법을 제공한다. Stories를 재사용해 자동 테스트를 구동하는데 사용할 수 있다.
  3. Stories는 단순히 어떻게 작동해야 하는지에 대해 정적인 디자인만을 보여주는 것이 아니라, UI가 실제로 작동하는 방식을 보여준다. 이를 통해 모든 사람이 현재 프로덕션에 대한 정보를 공유할 수 있다.

✅스토리북을 설치하자

스토리북이 어떤 것인지 위에서 확인을 했으니 실제로 사용해보자.

1
npx storybook@latest init

시작은 아래와 같이 할 수 있다.

1
npm run storybook

install 하면 .storybook.stories의 폴더가 생성된다. run하면 localhost:6006 페이지를 안내해준다.

✅스토리란?

새로 생긴 파일들을 살펴보기 앞서 먼저 스토리가 무엇인지 살펴보면, 공식문서에서는 이렇게 설명한다.

스토리는 UI 컴포넌트의 렌더링된 상태를 캡처한다. 개발자는 한 컴포넌트당 그 컴포넌트가 지원할 수 있는 모든 상태를 설명하는 스토리를 여러 개 작성한다.

이렇게만 보니 좀 어려워서 예제들을 살펴보면서 이해하고자 한다.

✅Button

stories 폴더를 여니 기본적으로 3개의 컴포넌트가 형성되었다. 이 중에서 버튼을 살펴보자.

1
2
3
4
stories/
├── button.css
├── Button.jsx
└── Button.stories.js

✅Button.stories.ts(tsx)

코드를 하나하나 살펴보자

➡️ 메타데이터 정의하기

Button.stories.ts(tsx)에서 메타데이터를 정의하고, 해당 메타데이터를 내보내 스토리북을 구성할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import type { Meta, StoryObj } from "@storybook/react"
import { Button } from "./Button" 👈

const meta = {
  title: "Example/Button",
  component: Button,  👈
  parameters: {
    layout: "centered",
  },
  tags: ["autodocs"],
  argTypes: {
    backgroundColor: { control: "color" },
  },
} satisfies Meta<typeof Button>;

export default meta;

Button.tsx로 만든 컴포넌트를 가져와 메타데이터에서 해당 컴포넌트를 사용함을 알려준다.

여기서 meta 변수는 Button 컴포넌트의 메타데이터를 정의한다! 또한, 기본적으로 제공하는 Meta 타입을 따르게 된다.

➡️ 스토리 정의하기

아래와 같이 Button의 Primary story를 정의할 수 있다. 여기서 args안에 작성된 값은 Button.tsx 파일의 props로 전달되어, button 컴포넌토를 다양하게 바꾸어주는 역할을 한다. 자세한 내용은 아래에 서술한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
type Story = StoryObj<typeof Button>

export const Primary: Story = {
  args: {
    primary: true,
    label: "Button",
  },
}

export const Secondary: Story = {
  args: {
    label: "Button",
  },
}

export const Large: Story = {
  args: {
    size: "large",
    label: "Button",
  },
}

export const Small: Story = {
  args: {
    size: "small",
    label: "Button",
  },
}

✅Button.tsx

이번엔 Button 컴포넌트를 살펴보자!

➡️Props 타입 정의

interface를 이용해 Props의 타입을 정의하고 있다. 예제에는 아래와 같은 내용을 사용하고 있다.

1
2
3
4
5
6
7
interface ButtonProps {
  primary?: boolean
  backgroundColor?: string
  size?: "small" | "medium" | "large"
  label: string
  onClick?: () => void
}

➡️UI 정의

기존에 알고 있던 컴포넌트 정의 방식을 사용한다. 만들어 둔 css 파일을 불러와준 다음 props를 구조분해 할당하고, 정의 해둔 Type을 적용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React from "react"
import "./button.css"

export const Button = ({
  primary = false,
  size = "medium",
  backgroundColor,
  label,
  ...props
}: ButtonProps) => {
  const mode = primary
    ? "storybook-button--primary"
    : "storybook-button--secondary"
  return (
    <button
      type="button"
      className={["storybook-button", `storybook-button--${size}`, mode👈].join(
        " "
      )}
      {...props}
    >
      {label}
      <style jsx>{`
        button {
          background-color: ${backgroundColor};
        }
      `}</style>
    </button>
  )
}

⚙️ mode 변수의 역할

먼저 primary 값에 따라, mode에 값을 할당한다. 해당 mode는 classname으로 사용된다. 여기서 primary의 기본 값은 false로 주었다.

1
2
3
const mode = primary
  ? "storybook-button--primary"
  : "storybook-button--secondary"

⚙️ props를 이용한 스타일링

사이즈를 동적으로 지정해준다. props로 받은 size를 이용해 해당 컴포넌트의 크기를 적절히 변경한다.

1
2
3
4
5
6
7
<button
  type="button"
  className={["storybook-button", `storybook-button--${size}`, mode].join(" ")}
  {...props}
>
  {label}
</button>

⚙️ styled-jsx

이 부분은 조금 낯설었는데, styled-jsx로, Next js에서 사용하는 CSS-in-JS 방식 스타일링 방법이다! 이를 이용해, 버튼 컴포넌트의 배경색을 backgroundColor props에 지정된 값으로 설정할 수 있다!

1
2
3
4
5
<style jsx>{`
  button {
    background-color: ${backgroundColor};
  }
`}</style>

📩마무리

다음은 args와 parameters 사용법을 정리해봐야겠다.😎

🗂️참고 사이트

This post is licensed under CC BY 4.0 by the author.