TIL - Storybook : docgenInfo를 활용하여 반복되는 코드 추상화

신혜린·2023년 8월 7일
0

TIL

목록 보기
6/19
post-thumbnail

Storybook에서 사용하는 args 중에 특정 args(props)만 제외하고 나머지는 disable하고 싶었는데, 동일 코드가 계속 반복되고 있어서 더욱 알아보기 쉽고 간략하게 추상화해보고자 함.

의도한 디스플레이 모습

StyledButton 이라는 UI 요소를 만들고 이를 storybook에 업로드한 상태.

  • Playground 에서는 width, size, color, outlined, disabled, loading, Type args(props)들을 사용해서 한번에 여러 args(props)의 모습을 확인할 수 있다.

  • size 에서는 size 만 조절해서 나타내볼 수 있도록 나머지 args(props)들은 disable시켜 디스플레이 되지 않도록 함.

  • width 등 다른 args(props) 컨트롤 판에서도 마찬가지.


수정 전

const Playground = (props) => React.createElement(StyledButton, props);
Playground.args = {
  width: 'auto',
  size: 'medium',
  color: 'primary',
  outlined: false,
  disabled: false,
  loading: false,
};

const size = Playground.bind({});
size.args = {
  size: 'x-large',
};
// 사용하지 않을 Prop의 경우 아래와 같이 설정해줍니다.
// 변수명과 동일한 Prop을 제외한 나머지 Prop은 control과 table에서 사용하지 않도록 해줍니다.
size.argTypes = {
  width: { table: { disable: true } },
  color: { table: { disable: true } },
  outlined: { table: { disable: true } },
  disabled: { table: { disable: true } },
  loading: { table: { disable: true } },
  Type: { table: { disable: true } },
};

const width = Playground.bind({});
width.args = {
  width: 200,
};
width.argTypes = {
  size: { table: { disable: true } },
  color: { table: { disable: true } },
  outlined: { table: { disable: true } },
  disabled: { table: { disable: true } },
  loading: { table: { disable: true } },
  Type: { table: { disable: true } },
};
...

위의 코드를 보면 다음과 같은 코드가 반복되고 있는 것을 볼 수 있다.

.argTypes = {
  width: { table: { disable: true } },
  color: { table: { disable: true } },
  outlined: { table: { disable: true } },
  disabled: { table: { disable: true } },
  loading: { table: { disable: true } },
  Type: { table: { disable: true } },
};
  • argTypes 앞에 나오는 size, width 는 컨트롤 판에 나타내고자 하는 특정 arg 를 나타내며, 특정 arg 를 제외한 나머지 args들을 disable해서 storybook의 control 판에 나타나지 않도록 하는 게 의도한 바.

  • 동일한 코드가 계속해서 반복되는 게 비효율적일 뿐만 아니라, 다른 사람들이 보고 이해하기 어렵다는 단점이 있다.



수정 후

docgenInfo를 활용하여 추상화

const argsNames = Object.keys(StyledButton.__docgenInfo.props);

const disableUnusedArgs = (argsNames, usedArg) => {
  return argsNames.reduce((disabledArgs, currentArg) => {
    if (currentArg === usedArg) return disabledArgs;
    return {
      ...disabledArgs,
      [currentArg]: { table: { disable: true } },
    };
  }, {});
};

const size = Playground.bind({});
size.argTypes = disableUnusedArgs(argsNames, 'size');

const width = Playground.bind({});
width.argTypes = disableUnusedArgs(argsNames, 'width');

코드 한 줄씩 뜯어보기

const argsNames = Object.keys(StyledButton.__docgenInfo.props);

StyledButton.__docgenInfo

  • docgenInfo를 통해 StyledButton의 객체에 접근할 수 있다.

StyledButton.__docgenInfo.props

  • 그 중에서도 우린 args(props)들을 다룰 거기 때문에 props의 키값에 접근할 후, 키값들을 argsName 이라는 변수에 배열로 할당.
    console.log(argsName) 을 찍어보면 위와 같이 콘솔창에 찍힌다.

const disableUnusedArgs ...

const disableUnusedArgs = (argsNames, usedArg) => {
  return argsNames.reduce((disabledArgs, currentArg) => {
    if (currentArg === usedArg) return disabledArgs;
    return {
      ...disabledArgs,
      [currentArg]: { table: { disable: true } },
    };
  }, {});
};

disableUnusedArgs = (argsNames, usedArg)

  • 사용하지 않는 args들은 disable시키는 함수라는 의미를 부여.
  • argsNames는 위에서 할당시킨 argsNames를 뜻함.
  • usedArg는 우리가 able시킬 arg를 담을 곳을 뜻함.

argsNames.reduce(disabledArgs, currentArg) => return ..., {})

  • reduce 함수를 이용하여 argsNames 배열 내 요소들을 하나씩 순환하여 반환.
  • 위에서 할당시킨 argsNames 배열 내 disable시킬 arg 요소들만 추출하여 disabledArg 에 담아줄 것.
  • (disabledArgs의 초기 상태는 {})

if (currentArg === usedArg) return disabledArgs

  • 현재 reduce 함수를 통해 배열을 하나씩 돌면서 [currentArg]: { table: { disable: true } },을 실행시켜주고 있는 상태.
  • 그러다 currentArg에 담길 arg가 우리가 able 시킬 arg(usedArg)인 경우를 마주했을 때엔 패스하고 disabledArgs를 그대로 반환.
이렇게 하면 `[currentArg]: { table: { disable: true } },` 를 실행시키지 않기 때문에 disable시키지 않고 그대로 두게 된다.


수정 전/후 비교

// 수정 전
size.argTypes = {
  width: { table: { disable: true } },
  color: { table: { disable: true } },
  outlined: { table: { disable: true } },
  disabled: { table: { disable: true } },
  loading: { table: { disable: true } },
  Type: { table: { disable: true } },
};

// 수정 후
size.argTypes = disableUnusedArgs(argsNames, 'size');

훨씬 더 간결해졌음을 볼 수 있다.


💡 TIL
추상화하는 것과는 별개로 초반에 disableUnusedArgs 함수를 정의하면서 argsprops 라는 용어를 모두 사용하여 혼란을 야기시켰었는데, 협업이 중요한 개발자 문화 내에서는 💫내 코드를 남이 봤을 때 이해하기 쉬울 수 있도록 더 고민하고 생각하면서 명명하는 것이 중요💫하다는 것을 느꼈다.

// 1차 수정
const disableArgs = (propNames, prop) => {
  return argsNames.reduce((acc, currentProp) => {...}

처음에는 위와 같이 어떤 arg를 disable할 것인지 함수명도 정확하지 않았을 뿐더러, acc, currentProp, disableArgs와 같이 무엇을 뜻하는 건지 잘 모르겠는 변수명들을 섞어가며 사용했다.

// 2차 수정
const disableUnusedArgs = (argsNames, usedArg) => {
  return argsNames.reduce((disabledArgs, currentArg) => {...}

이렇게 사용하지 않는 arg들은 disable할 것이라는 명확한 의미를 담은 함수명으로 재정의하고, props를 args로 통일시켰으며, acc 대신 disable될 arg들을 담을 곳임을 알 수 있도록 변수명을 변경하였다.

profile
개 발자국 🐾

0개의 댓글