React + TypeScript + StoryBook 스무스하게 사용하기

 

🤔 넌 왜 쓰니?

내가 처음 storybook을 배워야 겠다고 생각한 것은 공통 컴포넌트를 만들고 싶어서였다. 프로젝트를 만들 때마다 비슷하지만 조금씩 다른 UI요소들을 볼 때마다 새로 만들곤 했다. 뭔가 코드 낭비 같기도 하고 시간도 오래걸려서 이 문제를 해결할만한 도구가 없을까 고민하다가 storybook이란 것을 발견했다. 그래서 꼭 "배워야지.. 배워야지..." 미루다 지금와서야 공부를 시작한다.

 

🙃 Storybook이란?

사용해보니 storybook은 내가 생각한 장점 말고도 훨씬 더 많은 장점을 가지고 있었다. 컴포넌트를 어디서 부터 만들어야 할지 모르겠다면 storybook을 사용해라!

 

storybook은 자연스럽게 컴포넌트 주도의 개발을 하게 해준다. 예를 들어 TextField를 만든다고 가정하자. TextField를 만들려면 input란, 성공 및 실패 아이콘, 에러메세지 란 등등 필요한 구성요소들이 있다. 이것들 각각을 컴포넌트로 만들어서 관리하다 보면 중복되는 곳에 또 사용할 수 있다. 즉, 가장 기본적이고 독립적인 컴포넌트부터 개발을 하게 되기에 컴포넌트 주도 개발을 할 수 있으며 재사용성 또한 증가한다.

 

그리고 내가 어떤 컴포넌트를 만들었는지도 한눈에 확인하기 쉽다. 코드로만 작성되어 있다면 이게 무슨 UI인지 확인하기 어렵지만 storybook에서는 어떤 UI인지 눈으로 확인할 수 있기 때문에 좋은것 같다.

 

마지막으로 디자이너들과 협업하기 좋다. 스토리북을 배포한 링크를 디자이너들에게 보여주면 되기 때문에 일일이 코드를 실행시켜 보여줄 필요가 없다.

 

그리고 내 생각엔 이런점도 좋은거 같다. 예를들어 결제 페이지의 UI인 경우 개발자가 로그인을 하고 물건을 담아서 결제페이지까지 가야 볼 수 있다. 이럴때 storybook을 사용한다면 바로 확인할 수 있다는 장점이 있는거 같다.

 

🎇 사용방법

공식문서에 아주 자세하게 프레임워크별로 설치 방법이 나와 있으니 이것을 보고 따라하자

 

 

Get started with Storybook • Storybook docs

Storybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. It’s open source and free.

storybook.js.org

 

만약 storybook이 설치가 다 되었다면 stories 폴더안에 스토리와 컴포넌트가 같이 있을 것이다. 나는 이것을 따로 관리하는 것이 더 보기 편할 거 같아서 분리해줬다.

 

 

1️⃣ 컴포넌트 제작하기

예를들어 button 컴포넌트를 만들다고 가정하겠다. 이 버튼은 클릭 되었을 때랑 아닐 때 2가지 버전이 있다. 그럼 우리는 버튼의 클릭이벤트, 버튼 이름, 체크되었는지 안되었는지 확인 하는 값, 총 3가지가 필요하다.

 

 

interface ITagButton {
  children: string;
  isChecked: boolean;
  onClick?: () => void;
}

export default function TagButton({ children, onClick, isChecked }: ITagButton) {
  const buttonStyle = isChecked ? "bg-white text-primary" : "text-white bg-dark-opacity";
  return (
    <button
      className={`text-sm font-medium rounded-tag-button px-[10px] border border-white h-[33px] ${buttonStyle}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

 

우선 interface로 필요한 요소들을 정의해준다. 이후 컴포넌트를 만들어서 값을 넣어준다. 

나는 tailwindCSS를 사용해서 checked 값에 따라 스타일링을 다르게 해줬다.

 

2️⃣ 스토리 제작하기

import type { Meta, StoryObj } from "@storybook/react";

import TagButton from "../components/TagButton";

const meta = {
  title: "Buttons/TagButton",
  component: TagButton,
  parameters: {
    layout: "centered",
  },
  tags: ["autodocs"],
  argTypes: {
    children: {
      control: "text",
      description: "버튼의 텍스트",
      defaultValue: "button",
    },
    isChecked: {
      control: "boolean",
      description: "버튼 활성화 여부",
      defaultValue: true,
    },
    onClick: { action: "clicked", description: "버튼 클릭 이벤트" },
  },
} satisfies Meta<typeof TagButton>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
  args: {
    children: "button",
    isChecked: false,
  },
};

 

story는 처음 보기 때문에 meta객체에 있는 요소들을 하나씩 살펴보겠다.

 

title : 스토리북에 위치시킬 곳을 나타낸다. (Button이란 폴더에 TagButton파일이 있는 느낌이다.)
component : 해당 스토리에 맞는 컴포넌트를 써준다.
parameters : storybook에서의 요소 위치
argTypes : storybook에서 컨트롤 할 수 있는 값이다. (컴포넌트를 만들 때 사용했던 요소들을 적어준다.)

 


 

이렇게 만들어진 컴포넌트는 아래와 같이 쓰인다.

<TagButton
  key={tag}
  isChecked={tag === selectedTag}
  onClick={() => {
    setSelectedTag(tag);
  }}
>
  리스트
</TagButton>