리액트로 이것저것 해보면서 컴포넌트를 테스트 할 수 있는 storybook이란 것을 알게되었고 사용해야 했다. 뭐든 처음이 그렇듯 설정과 시작이 힘들지만 하나하나 공부하면서 남겨본다.
우선 다른 블로그에서도 많은 가이드를 제시했다. -g로 스토리북을 설치해서 storybook/cli의 getstorybook을 통해 프로젝트로 가져오는 형식도 있었으나, learnstorybook이라는 페이지가 정성스럽게 만들어져 있어 여기를 참고하여 최대한 제시하는 방향을 따라갔다.
CRA를 통해 프로젝트 생성한 후 스토리북을 설치한다.
(CRA는 간단하게 npx create-react-app
명령어를 입력해 생성해주면 된다)
그리고
npx -p @storybook/cli sb init
를 입력해 스토리북cli를 설치하고 init을 진행한다.
이 사이트에서는 yarn을 사용할 것을 추천하고있다. yarn으로 따라해보자.
설치가 완료 된 후 yarn storybook을 입력하면 콘솔에 스토리북이 실행되었다는 메세지가 나오고 브라우저에 스토리북 화면이 나온다.
이상태에서 튜토리얼에서 제공하는 CSS 와 assets 파일들을 다운로드 해준다.
CSS는 이링크의 CSS를 복사해서 index.css에 붙여넣으면 되고,
assets는
npx degit chromaui/learnstorybook-code/src/assets/font src/assets/font
npx degit chromaui/learnstorybook-code/src/assets/icon src/assets/icon
를 입력하면 자동으로 src/assets에 다운로드 된다.
이후 src/components 폴더에 Task.js와 Task.stories.js를 생성한다.
// src/components/Task.js
import React from 'react';
export default function Task({ task: { id, title, state }, onArchiveTask, onPinTask }) {
return (
<div className="list-item">
<input type="text" value={title} readOnly={true} />
</div>
);
}
// src/components/Task.stories.js
import React from 'react';
import Task from './Task';
export default {
component: Task,
title: 'Task',
};
const Template = args => <Task {...args} />;
export const Default = Template.bind({});
Default.args = {
task: {
id: '1',
title: 'Test Task',
state: 'TASK_INBOX',
updatedAt: new Date(2018, 0, 1, 9, 0),
},
};
export const Pinned = Template.bind({});
Pinned.args = {
task: {
...Default.args.task,
state: 'TASK_PINNED',
},
};
export const Archived = Template.bind({});
Archived.args = {
task: {
...Default.args.task,
state: 'TASK_ARCHIVED',
},
};
그리고 .storybook의 main.js와 preview.js를 바꿔준다.
//main.js
module.exports = {
//👇 Location of our stories
stories: ['../src/components/**/*.stories.js'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/preset-create-react-app',
],
};
//preview.js
import '../src/index.css'; //👈 The app's CSS file goes here
//👇 Configures Storybook to log the actions( onArchiveTask and onPinTask ) in the UI.
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
};
이렇게 프로젝트의 .storybook의 설정을 바꾸고 나서 다시 yarn storybook을 실행해주면
이렇게 우리가 붙여넣은 설정들이 적용되어있다.
그리고 Task.js에 간단한 구현을 추가한다.
// src/components/Task.js
import React from 'react';
export default function Task({ task: { id, title, state }, onArchiveTask, onPinTask }) {
return (
<div className={`list-item ${state}`}>
<label className="checkbox">
<input
type="checkbox"
defaultChecked={state === 'TASK_ARCHIVED'}
disabled={true}
name="checked"
/>
<span className="checkbox-custom" onClick={() => onArchiveTask(id)} />
</label>
<div className="title">
<input type="text" value={title} readOnly={true} placeholder="Input title" />
</div>
<div className="actions" onClick={event => event.stopPropagation()}>
{state !== 'TASK_ARCHIVED' && (
// eslint-disable-next-line jsx-a11y/anchor-is-valid
<a onClick={() => onPinTask(id)}>
<span className={`icon-star`} />
</a>
)}
</div>
</div>
);
}
이후 스토리북으로 확인하면 마크업과 CSS가 결합하여 UI를 생성하며, 전체 앱을 실행시키지 않고 컴포넌트를 만들게 된 셈이다.
스토리북이 간단한 줄 알았는데 생각보다 할게 많다. 설정도 해야하고 .stories.js파일도 만들어야하고 이것저것 찾아가며 진행하려니 너무 더딘 느낌이다. 하지만 조금만 잘 다루게 되면 컴포넌트를 만들어가는데 굉장히 도움이 될 것 같다.