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함수를 정의하면서args와props라는 용어를 모두 사용하여 혼란을 야기시켰었는데, 협업이 중요한 개발자 문화 내에서는 💫내 코드를 남이 봤을 때 이해하기 쉬울 수 있도록 더 고민하고 생각하면서 명명하는 것이 중요💫하다는 것을 느꼈다.// 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들을 담을 곳임을 알 수 있도록 변수명을 변경하였다.