스토리북 맛보기

2022. 5. 26. 07:50UX Engineer 이야기
ny.back

들어가며

예전 RPA 프로젝트에서 PL님이 사용하셔서 한번 사용해보고 편하다고 생각했었던 스토리북을 다음 프로젝트에서 사용한다는 이야기를 듣고 스터디 겸 모르시는 분들께도 간단하게나마 공유드리면 어떨까 하여 해당 주제를 선정하여 소개하고자 합니다.

스토리북이란?

스토리북은 컴포넌트 기반의 뷰를 위한 독립적인 UI 개발 환경입니다.

처음 리액트를 기반으로 개발되었고, 이후 Vue, Angular, Web Components, Svelte 등 다양한 프레임워크를 지원하고 있습니다.

스토리북은 컴포넌트를 목록화하여 보고 싶은 컴포넌트를 언제든 확인 가능하도록 만들어줍니다.
하나의 디자인 시스템이라고 생각하시면 편하실 것 같네요.

스토리북의 컴포넌트는 Mockup 상태 값을 넣어줄 수 있도록 되어있어 각종 상태 값에 따라 바로바로 디자인이 변경되는 것을 확인하실 수 있고 또한, 각 개체별로 볼 수도 있지만 페이지 단위로 여러 가지 컴포넌트를 묶어 보여줄 수도 있습니다.

위와 같은 기능을 제공함으로써 개발 요건을 반영하여 기획, 디자인 파트와 같이 확인하며 협업이 가능합니다.
스토리북을 확인하면서 여러 케이스를 미리 테스트할 수 있고 이렇게 검수를 선진행하여 수정이 필요한 경우 빠르게 확인한 내용을 반영하여 작업함에 있어 수월하게 진행할 수 있도록 도와줍니다.

그럼 스토리북에 대한 설명은 이쯤에서 마무리하고 실제로 설치를 진행해볼까요?

스토리북을 설치해보자

스토리북을 사용하려면 사용 기반의 프레임워크를 먼저 설치해야겠죠?

저는 리액트를 기반으로 설정해보았습니다.

리액트를 처음 설치하시는 분들을 위해 설치 코드도 선언해두었습니다.

npx create-react-app my-app

my-app 부분은 본인이 사용할 프로젝트명을 입력해주시면 됩니다.

리액트 설치 후

npx -p @storybook/cli sb init

을 선언하여 스토리북을 설치해줍니다.

설치가 완료된 후 package.json을 살펴보시면 devDependencies에 스토리북 관련 기능들이 종속되어있는 것을 볼 수 있습니다.

script도 개발 환경에서 실행할 수 있게, 실행 및 빌드 관련 스크립트 코드가 추가된 것을 확인하실 수 있습니다.

.storybook 폴더가 생긴 것을 확인하실 수 있는데 안을 살펴보면 2개의 파일이 생성되어있습니다.

main.js 는 스토리북 자체의 구성 파일이라고 할 수 있고, preview.js 는 사용자가 작성하는 스토리의 구성 파일이라고 생각하시면 됩니다.

참고경로 : Storybook > Sorting stories

위의 경로의 해당 코드를 복사하여 preview.js 에 넣어주시면
스토리 목록이 문자 순서로 정렬됩니다.

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  // storybook에서 가져온 코드
  options: {
    storySort: (a, b) =>
      a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, undefined, { numeric: true }),
  }
}

이와 같이 스토리북에서 제공하는 기본적인 소스들을 넣어 커스텀이 가능합니다.

그럼 이제 본격적으로 스토리를 만들어볼까요?

스토리 만들기

src > stories 폴더를 보시면 파일들이 생성되어있으나 바로 수정 적용하기엔 영향받는 것들이 많아
components 폴더를 만들어 기존 파일들을 조금 수정하여 설명드리겠습니다.

제일 간단한 버튼 컴포넌트를 볼까요?

하나의 컴포넌트를 만들려면 3개의 파일 Button.js / Button.css / Button.stories.js 가 필요합니다.

Button.js

Button.js 에는 버튼 컴포넌트를 생성하고 불러올 클래스에 대한 정의를 설정해줍니다.

import React from 'react';
// 해당 버튼 컴포넌트에 적용할 Button.css를 import로 연결
import './Button.css';

// 버튼 컴포넌트 구성
export const Button = ({ buttonstate, size, label, ...props }) => {
  // buttonstate : 버튼 상태 제어
  // size : 버튼 사이즈 제어
  // label : 버튼 내부 텍스트
  // ...props : 그 외 다양한 값 넘길 때
  return (
    <button type="button"
            className={`button ${buttonstate} ${size}`}
            {...props}
    >
      {label}
    </button>
  );
};

// 아무것도 설정하지 않았을 경우 default로 보이는 상태 값 설정
Button.defaultProps = {
  buttonstate: 'secondary',
  size: 'medium',
  onClick: undefined,
};

Button.css

Button.css 에는 Button과 관련된 css 스타일 클래스를 생성해주면 됩니다.

그리고 작업이 완료되면 Button.js 에 import 시켜주면 됩니다. (Button.js 예시 주석 참고)

/* 버튼의 기본 스타일*/
.button {
  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 700;
  border: 0;
  border-radius: 3em;
  cursor: pointer;
  display: inline-block;
  line-height: 1;
}
/*버튼의 상태별 스타일*/
.primary {
  color: white;
  background-color: #1ea7fd;
}
.secondary {
  color: #333;
  background-color: transparent;
  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
}
.danger {
  color: white;
  background-color: #e73124;
}
.small {
  font-size: 12px;
  padding: 10px 16px;
}
.medium {
  font-size: 14px;
  padding: 11px 20px;
}
.large {
  font-size: 16px;
  padding: 12px 24px;
}

다음은 Button.stories.js인데요.
Button.js 와 Button.css 에 많은 옵션을 정해준다 해도 해당 파일에 선언해주지 않으면 스토리북에 노출되지 않습니다.

Button.stories.js
Button.stories.js 에는 Button.js를 import 시켜주고 왼쪽 패널에서 쉽게 찾을 수 있도록 타이틀 및 컴포넌트 데이터를 설정해준 후 js에서 설정해둔 버튼 컴포넌트 종류들을 나열하여 출력하도록 해줍니다.

import React from 'react';
// 스토리북에 노출할 컴포넌트를 import 해줍니다.
import { Button } from './Button';

export default {
  title: 'Components/Button',
  component: Button
};

export const Primary = (args) => <Button buttonstate='primary' label='Primary'></Button>
export const Secondary = (args) => <Button buttonstate='secondary' label='Secondary'></Button>

생성할 컴포넌트를 위와 같이 설정하여 노출시킬 수 있습니다.
하지만 옵션 값이 많아질수록 길어지게 되고 가독성이 떨어질 테지요.

반복되는 컴포넌트의 경우는 Template화 하여 사용할 수 있습니다.
Template화 되어있는 코드가 스토리북에서 기본적으로 제공한 코드인데요.

import React from 'react';
import { Button } from './Button';

export default {
  title: 'Components/Button',
  component: Button
};

// option 값을 args에 넣어 Button Template을 생성해줍니다.
// 반복적으로 사용하는 공통 스타일 코드의 경우 Template화 하면 좋겠죠.
const Template = (args) => <Button {...args} />;

// 각 버튼 스타일을 선언해주고 Template을 만든 것을 bind 해주어 연결시켜줍니다.
export const Primary = Template.bind({});
// 상태별로 적용해야 할 option 값을 설정해줍니다.
Primary.args = {
  buttonstate: 'primary',
  label: 'Button',
};

export const Secondary = Template.bind({});
Secondary.args = {
  // Secondary의 경우 Button.js 에 defaultProps로 기본값 설정을 해주었기에 primary는 선언하지 않았습니다.
  label: 'Button',
};

export const Danger = Template.bind({});
Danger.args = {
  buttonstate: 'danger',
  label: 'Button',
};

export const Large = Template.bind({});
Large.args = {
  size: 'large',
  label: 'Large Button',
};

export const Medium = Template.bind({});
Medium.args = {
  // Medium도 마찬가지로 기본값 설정을 해주었기에 size는 선언하지 않았습니다.
  label: 'Medium Button',
};

export const Small = Template.bind({});
Small.args = {
  size: 'small',
  label: 'Small Button',
};

위의 코드를 작성 후 실행하면 아래와 같은 스타일들을 보실 수 있습니다.

스토리북 실행 시 노출되는 각 컴포넌트의 스타일


마치며

스토리북의 기본적인 컴포넌트 생성 작업을 소개해드렸는데요.

이 외에도 페이지 단위로 작업 진행한다거나 각 상태를 바로 체크할 수 있게 해주는 addons 사용법 등이 있는데 해당 부분은 다음에 조금 더 공부한 후 정리해보려고 합니다.
부족한 글이지만 읽어주셔서 감사합니다.😊

그럼 안녕히...👋 -The End-

이 글은 pxd XE Group Blog에서도 보실 수 있습니다.

참고문서