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들을 담을 곳임을 알 수 있도록 변수명을 변경하였다.