Skip to content

StoryBook

JihyeSeo1120 edited this page Mar 6, 2020 · 2 revisions

StoryBook

์ฐธ๊ณ ๋งํฌ

  1. velopert๋ธ”๋กœ๊ทธ
  2. ๊ณต์‹๋ฌธ์„œ
  3. Say Hello to Storybook: ์Šคํ† ๋ฆฌ๋ถ์„ ํ†ตํ•œ React UI ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ

์™œ ์‚ฌ์šฉํ• ๊นŒ

ํŽ˜์ด์ง€ ๋‹จ์œ„์˜ ๊ฐœ๋ฐœ์ด ์ด๋ฃจ์–ด์ง€๋˜ ๊ณผ๊ฑฐ์™€ ๋‹ฌ๋ฆฌ ์š”์ฆ˜์˜ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์€ ์ฃผ๋กœ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค. ์›๋ž˜ ์ปดํฌ๋„ŒํŠธ๋Š” ์™ธ๋ถ€ ์ƒํƒœ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€์•Š๋Š” ๋…๋ฆฝ๋œ ๊ฐœ์ฒด๋กœ์„œ, ๊ณ ๋ฆฝ๋œ ํ™˜๊ฒฝ์—์„œ๋„ ์ž์‹ ๋งŒ์˜ ์Šคํƒ€์ผ๊ณผ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. React์˜ ์ปดํฌ๋„ŒํŠธ ์ •์˜์— ๋”ฐ๋ฅด๋ฉด, ์ปดํฌ๋„ŒํŠธ๊ฐ€ UI๋ฅผ ๋…๋ฆฝ์ ์ด๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ๊ฐ ๋‹จ์œ„๋ฅผ ๊ณ ๋ฆฝํ•ด์„œ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค๊ณ  ์„ค๋ช…ํ•œ๋‹ค.

์ด๋Ÿฐ ์ •์˜์— ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„์˜ ๊ฐœ๋ฐœ์€ container(๋กœ์ง๊ณผ state) ์™€ presenter(container๊ฐ€ ๋„˜๊ฒจ์ฃผ๋Š” props์— ๋”ฐ๋ผ ์‹ค์ œ๋กœ ๋ณด์—ฌ์ง€๋Š” ๋ถ€๋ถ„)์˜ ๊ตฌ์„ฑ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ ์ด๋Ÿฐ ๋ฐฉ์‹์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜จ์ „ํžˆ ๋ทฐ์— ์ง‘์ค‘ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ํ•œ๋‹ค.

Storybook์€ ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š”, ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„์˜ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์ง€์›ํ•˜๋Š” ๋„๊ตฌ๋‹ค. ์œ„์—์„œ ๋งํ•œ presenter๋ถ€๋ถ„์„ ๋…๋ฆฝ์ ์œผ๋กœ ๋ฌถ์–ด์คŒ์œผ๋กœ์จ ๋ทฐ๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ๊ณ ๋ฆฝ๋œ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ด์„œ ๊ด€์‹ฌ์‚ฌ๋ฅผ ์˜์กด์„ฑ๊ณผ ํ™˜๊ฒฝ์œผ๋กœ๋ถ€ํ„ฐ ๋ถ„๋ฆฌ์‹œ์ผœ ์ค€๋‹ค.

์„ค์น˜ ๋ฐฉ๋ฒ•

๋ฆฌ์•กํŠธ ๊ธฐ์ค€

  1. CRA x
mkdir ํด๋”์ด๋ฆ„
cd ํด๋”์ด๋ฆ„
yarn init -y # ๋˜๋Š” npm init -y
npx -p @storybook/cli sb init --type react
  1. CRA o
create-react-app ์œผ๋กœ ๋งŒ๋“  ํด๋”์—์„œ
npx -p @storybook/cli sb init --type react_scripts
  1. ์ƒ์„ฑ๋œ ๋””๋ ‰ํ† ๋ฆฌ ๋ชจ์Šต

ํด๋” ๊ฒฐ๊ณผ

  • main.js : ์Šคํ† ๋ฆฌ๋ฅผ ์–ด๋””์„œ๋ถ€ํ„ฐ ๋ถˆ๋Ÿฌ ์˜ฌ์ง€ ์ ํ˜€์žˆ๋‹ค.
module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links'],
};
  1. srcํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  storiesํด๋”๋ฅผ src์•ˆ์œผ๋กœ ์˜ฎ๊ธด ํ›„ ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๊พผ๋‹ค.
stories: ['../src/**/*.stories.js']
  • ๋ฐ”๋€ ๋””๋ ‰ํ† ๋ฆฌ ๋ชจ์Šต
  1. ์‹คํ–‰ ๋ช…๋ น์–ด
npm run storybook / yarn storybook

๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

  1. ๊ฐ„๋‹จํ•œ Hello ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด srcํด๋” ์•„๋ž˜ Helloํด๋”๋ฅผ ๋งŒ๋“ค๊ณ  Hello.jsํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค.
  • src/Hello/Hello.js
import React from 'react';

const Hello = ({ name, big }) => {
  if (big) {
    return <h1>์•ˆ๋…•ํ•˜์„ธ์š”, {name}!</h1>;
    //big์ด๋ผ๋Š” props๊ฐ€ ์ฃผ์–ด์ง€๋ฉด h1์„ ๋žœ๋”๋ง
  }
  return <p>์•ˆ๋…•ํ•˜์„ธ์š”, {name}!</p>;
  //์•„๋‹ˆ๋ฉด p ๋žœ๋”๋ง
};

export default Hello;
  1. ์Šคํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ ๋‹ค. ์Šคํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ํ™•์žฅ์ž๋Š” .stories.js์ด๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ผ์„œ ์Šคํ† ๋ฆฌ๊ฐ€ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ ์Šคํ† ๋ฆฌ๋Š” ํŽ˜์ด์ง€ ๋‹จ์œ„๊ฐ€ ๋ ์ˆ˜๋„ ์žˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž์˜ ์„ ํƒ์ด๋‹ค.

  • src/Hello/Hello.stores.js
import React from 'react';
import Hello from './Hello';

export default {
  title: 'components|basic/Hello', 
  // title : ์Šคํ† ๋ฆฌ๋ถ์—์„œ ๋ณด์—ฌ์งˆ ๊ทธ๋ฃน๊ณผ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œ
  component: Hello 
  // component : ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฌธ์„œํ™” ํ• ์ง€ ๋ช…์‹œ
};

export const standard = () => <Hello name="Storybook" />;
export const big = () => <Hello name="Storybook" big />;
  • title: export default ๋ฅผ ํ†ตํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ๋‚ด๋ณด๋‚ผ ๋•Œ, title ๊ฐ’์€ ์Šคํ† ๋ฆฌ๋ถ์—์„œ ๋ณด์—ฌ์ง€๋Š” ๊ทธ๋ฃน๊ณผ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œํ•œ๋‹ค.
  1. ๊ฒฐ๊ณผ ํ™”๋ฉด

๊ฒฐ๊ณผํ™”๋ฉด

Addon์— ๋”ฐ๋ฅธ StoryBook ์‚ฌ์šฉ๋ฒ•

https://storybook.js.org/addons/ addon์— ๋Œ€ํ•œ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฝ์–ด๋ณด์‹œ๋Š” ๊ฒƒ์„ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

1. Knobs Addon

์ปดํฌ๋„ŒํŠธ์˜ props ๋ฅผ ์Šคํ† ๋ฆฌ๋ถ ํ™”๋ฉด์—์„œ ๋ฐ”๊ฟ”์„œ ๋ฐ”๋กœ ๋ฐ˜์˜์‹œ์ผœ์ค„ ์ˆ˜ ์žˆ๋Š” ์• ๋“œ์˜จ

  • ์„ค์น˜ ๋ฐฉ๋ฒ•
  1. ๋ช…๋ น์–ด ์‹คํ–‰
yarn add --dev @storybook/addon-knobs
๋˜๋Š” npm install --save-dev @storybook/addon-knobs
  1. .storybookํด๋”์˜ main.js์˜ addons์— '@storybook/addon-knobs/register'์ถ”๊ฐ€ํ•œ๋‹ค.
  • withKnob๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ๋“œ์˜จ์€ ์ ์šฉ

    • src/Hello/Hello.stories.js
    import React from 'react';
    import Hello from './Hello';
    import { withKnobs } from '@storybook/addon-knobs';
    
    export default {
      title: 'components|basic/Hello', // ์Šคํ† ๋ฆฌ๋ถ์—์„œ ๋ณด์—ฌ์งˆ ๊ทธ    ๋ฃน๊ณผ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œ
      component: Hello, // ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฌธ์„œํ™” ํ• ์ง€ ๋ช…์‹œ
      decorators: [withKnobs] 
      // ์• ๋“œ์˜จ ์ ์šฉ
      //export default๋กœ ๋‚ด๋ณด๋‚ด๋Š” ๊ฐ์ฒด ์•ˆ์— decorators ๋ผ๋Š” ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด์„œ ๊ทธ ์•ˆ์— withKnobs ๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.
    };
    
    export const standard = () => <Hello name="Storybook" />;
    export const big = () => <Hello name="Storybook" big />;
  • default ๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ Knobs๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒˆ๋กœ์šด ์Šคํ† ๋ฆฌ ๋งŒ๋“ค๊ธฐ

    • src/Hello/Hello.stories.js
    (...)
    export default {
      title: 'components|basic/Hello', // ์Šคํ† ๋ฆฌ๋ถ์—์„œ ๋ณด์—ฌ์งˆ ๊ทธ๋ฃน๊ณผ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œ
      component: Hello, // ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฌธ์„œํ™” ํ• ์ง€ ๋ช…์‹œ
      decorators: [withKnobs] // ์• ๋“œ์˜จ ์ ์šฉ
    };
    
    export const hello = () => {
      // knobs ๋งŒ๋“ค๊ธฐ
      const big = boolean('big', false);
      const name = text('name', 'Storybook');
      return <Hello name={name} big={big} />;
    };
    hello.story = {
      name: 'Default'
    };
    (...)
    • ๊ฒฐ๊ณผ ๊ฒฐ๊ณผ
    • ์•„๋ž˜ KnobsํŒจ๋„์—์„œ big์™€ name์„ ๋ฐ”๊ฟ”์„œ state๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค!
  • Knobs ๋ฅผ ์‚ฌ์šฉ ํ•  ๋•Œ ํ•„์š”ํ•œ ์ฃผ์š” ์ธ์ž

    1. Knobs ์˜ ์ด๋ฆ„
    2. ๊ธฐ๋ณธ๊ฐ’
    3. GROUP ID (optional)
    • ์˜ˆ์‹œ
    const big = boolean('big', false, 'Group 1');

2. Actions Addon

์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•˜์—ฌ ํŠน์ • ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋์„ ๋•Œ ์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ํ•จ์ˆ˜์— ์–ด๋–ค ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„ฃ์–ด์„œ ํ˜ธ์ถœํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์• ๋“œ์˜จ

  • ์•ก์…˜์„ ๋งŒ๋“ค ๋•Œ๋Š” **action('์•ก์…˜ ์ด๋ฆ„')**์ด๋ผ ํ•œ๋‹ค.
  • src/Hello/Hello.js
(...)
const Hello = ({ name, big, onHello, onBye }) => {
     return (
    <div>
    {big ? <h1>์•ˆ๋…•ํ•˜์„ธ์š”, {name}!</h1> : <p>์•ˆ๋…•ํ•˜์„ธ์š”, {name}!</p>}
    <div>
        <button onClick={onHello}>Hello</button>
        <button onClick={onBye}>Bye</button>
    </div>
    </div>
    );
};
    (...)
  • src/Hello/Hello.js
(...)
import { action } from '@storybook/addon-actions';

export default {
  title: 'components|basic/Hello', // ์Šคํ† ๋ฆฌ๋ถ์—์„œ ๋ณด์—ฌ์งˆ ๊ทธ๋ฃน๊ณผ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œ
  component: Hello, // ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฌธ์„œํ™” ํ• ์ง€ ๋ช…์‹œ
  decorators: [withKnobs] // ์• ๋“œ์˜จ ์ ์šฉ
};

export const hello = () => {
  // knobs ๋งŒ๋“ค๊ธฐ
  const big = boolean('big', false);
  const name = text('name', 'Storybook');
  return (
    <Hello
      name={name}
      big={big}
      onHello={action('onHello')}
      onBye={action('onBye')}
    />
  );
};
(...)
  • ๊ฒฐ๊ณผ ๊ฒฐ๊ณผ

3. Story Addon

story source๋ฅผ ํŒจ๋„์—์„œ ๋ณผ์ˆ˜ ์žˆ๋‹ค.

  • ์„ค์น˜ ๋ฐฉ๋ฒ•
  1. ๋ช…๋ น์–ด ์‹คํ–‰
yarn add --dev @storybook/addon-storysource
๋˜๋Š” npm install --save-dev @storybook/addon-storysource
  1. .storybookํด๋”์˜ main.js์˜ addons์— '@storybook/addon-storysource'์ถ”๊ฐ€ํ•œ๋‹ค.
  • ๊ฒฐ๊ณผ ๊ฒฐ๊ณผ

์–‘์ด ๋งŽ์•„์„œ ๊ณ„์† ์—…๋ฐ์ดํŠธ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹คใ… ใ