갑자기.. React 관련한 글이네요..ㅎㅎ
개인 노션에 정리해둔 게 계속 쌓여서 차근차근 블로그에 작성하고 있는 단계이고
오늘은 React Story Book에 대해 정리해보도록하겠습니다
소스 코드는 아래 GIT에서 확인 가능하십니다
https://github.com/jungHyeonS/React-stroybook
GitHub - jungHyeonS/React-stroybook: react-stroybook-study
react-stroybook-study. Contribute to jungHyeonS/React-stroybook development by creating an account on GitHub.
github.com
StoryBook 이 뭘까?
스토리북은 다양한 방식으로 사용되고 있는 UI 컴포넌트 개발 도구입니다. 단순히 회사 UI라이브러리를 내부 개발자들을 위해 문서화할 수도 있고, 외부 공개용 디자인 시스템을 개발하기 위한 기본 플랫폼으로도 사용할 수 있습니다
즉 컴포넌트들을 문서화할 수 있도록 도와주는 오픈소스 도구입니다
스토리북의 기본 구성단위는 스토리(Story)이며, 하나의 UI 컴포넌트는 보통 하나 이상의 Story를 가지게 됩니다
각 Story는 해당 UI 컴포넌트가 어떻게 사용될수 있는지 보여주는 하나의 예시입니다
스토리북을 사용하면 UI컴포넌트가 각각 독립적으로 어떻게 실제로 렌더링 되는지 직접 시각적으로 테스트하면서 개발을 진행할 수 있습니다
해당 UI라이브러리를 사용하는 개발자 입장에서도 코드를 보지 않고 미리 각 UI 컴포넌트를 체험해보고 사용할 수 있습니다
스토리북을 쓰는 이유
1. 개별 정돈의 편리합니다
2. 재사용성을 고려한 디자인과 개발이 가능합니다
3. 컴포넌트 테스트에 용이합니다
재사용성의 필요성
1. 불필요한 작업을 줄여줍니다
2. 안정적으로 검증된 코드를 사용할 수 있습니다
3. 캡슐화를 통해 테스트가 쉬워집니다
그러면 스토리북 예제 프로젝트를 개발해보도록 하겠습니다
해당 프로젝트는 CRA 기반으로 개발하였습니다
StoryBook 설치 및 세팅
npx -p @storybook/cli sb init
해당 명령어를 실행하게 되면 . storybook, src/stories 폴더가 생성되게 됩니다
.storybook : Storybook 설정 파일들이 포함된 폴더입니다
src/stories : Storybook 예제 컴포넌트 폴더 입니다
StoryBook 실행
package.json 파일을 열어보게 되면 storybook이라는 빌드 스크립트가 추가되어있습니다
npm run storybook
이 명령어를 입력하게 되면 아래와 같이 스토리북 로컬 화면이 실행되게 됩니다
이 포스팅 예제에서는 버튼 컴포넌트와 여러 개의 div로 구성되어있는 stack 컴포넌트를 만들어 보도록 하겠습니다
우선 src/stories 폴더를 보게 되면 많은 파일들이 있는데 전부다 삭제해주도록 하겠습니다
Button 컴포넌트 생성
src/components 폴더에 button 컴포넌트를 생성해보도록 하겠습니다
* prop-types 모듈은 npm install prop-types 해주시면 됩니다
Button 컴포넌트는 props로 label, backgroundColor, size, handleClick(클릭이벤트)를 받게 되며
이 props들은 이후 스토리를 만들 때 사용하게 됩니다
import PropTypes from "prop-types"
function Button({label,backgroundColor="red",size="md",handleClick}){
let scale = 1
if(size === "sm") scale = 0.75
if(size === "lg") scale = 1.5;
const style = {
backgroundColor,
padding : `${scale * 0.5}rem ${scale * 1}rem`,
border : "none"
}
return(
<button onClick={handleClick} style={style}>
{label}
</button>
)
}
Button.prototype = {
label : PropTypes.string,
backgroundColor : PropTypes.string,
size : PropTypes.oneOf(["sm","md","lg"]),
handleClick: PropTypes.func
}
export default Button
예제용 버튼 컴포넌트를 생성하였으니 이 버튼에 대한 스토리를 만들어보도록 하겠습니다
Button.stories 생성
우선 src/stories/Button.stories.js 파일을 생성을 하고 우선 아래 코드를 추가해줍니다
import Button from "../components/Button";
//실제 스토리 객체
export default {
title : "Components/Button",
component : Button,
argTypes : {handleClick : {action : "handleClick"}}
}
위에서 만든 Button 컴포넌트를 불러오고 실제 스토리에 해당하는 객체를 만들어줍니다
해당 객체에서 내가 만들 스토리에 제목(타이틀)과 어떤 컴포넌트를 지정할지에 대해 명시를 해주고
만약 클릭이벤트가 있다면 argTypes에 이벤트를 지정해주면 됩니다
title : 스토리의 제목
component : 스토리에 적용할 컴포넌트
argTypes : 컴포넌트에 이벤트
자 그러면 이상태 면 스토리가 만들어질까요?
아닙니다 위에서 작성한 Button 컴포넌트는 props들을 가지고 있기 때문에 해당 props들을 지정해줘야 합니다
자바스크립트에 bind를 이용을 해야 되기에 다음과 같은 코드를 작성합니다
const Template = args => <Button {...args}/>
export const Red = Template.bind({});
Red.args = {
backgroundColor : 'red',
label : 'Press me',
size : "md",
}
Button 컴포넌트를 리턴하는 Template 객체를 만들고
해당 객체에 args로 Button 컴포넌트에 Props들을 지정한 후에 전달합니다
그러면 backgroundColor, label, size Prop들이 Button 컴포넌트에 전달하게 됩니다
이후 저장한 후 스토리북 페이지를 한번 보도록 하겠습니다
아까 저희가 만든 Button 이 스토리북에 나오게 되었습니다, args로 지정한 backgroundColor, label, size도 정확하게 표시가 되었습니다
그리고 여기서 스토리북의 강점이 나옵니다, 우리가 만든 스토리에 Controls 부분을 조작해보면 저희가 입력한 대로 컴포넌트가 실행되는 것을 볼 수 있습니다
그리고 Red 컴포넌트 말고도 Green, small과 같은 이름의 컴포넌트를 추가적으로 만들고 싶다면
bind 객체를 아래와 같이 여러 개 만들면 됩니다
export const Green = Template.bind({});
Green.args = {
backgroundColor : 'green',
label : 'Press me',
size : "lg",
}
export const Small = Template.bind({});
Small.args = {
backgroundColor : 'red',
label : 'Press me',
size : "sm",
}
export const Large = Template.bind({});
Large.args = {
backgroundColor : 'red',
label : 'Press me',
size : "lg",
}
export const LongLabel = Template.bind({});
LongLabel.args = {
backgroundColor : 'red',
label : 'Press me assasdasdas dasdasdas dasdasdasdasdasd',
size : "md",
}
다음은 입력한 숫자만큼 div가 생성되는 stack 컴포넌트를 만들어보도록 하겠습니다
Stack 컴포넌트 생성
src/components/Stack.js 파일에 아래와 같이 생성하였습니다
여기서 중요한 점은 children props입니다
chidren은 stack 컴포넌트를 사용할 때 <stack></stack>과 같이 사용하게 되는데
이때 태그와 태그 사이에 모든 내용일 넘겨지게 됩니다
그 외는 Button 컴포넌트와 같이 props를 받고 컴포넌트를 그리게 됩니다
import PropTypes from "prop-types"
function Stack({children,spacing=2,direction="row",wrap=false}){
const style = {
display : "flex",
gap : `${spacing * 0.25}rem`,
flexWrap : wrap ? "wrap" : "nowrap",
flexDirection : direction
}
return <div style={style}>{children}</div>
}
Stack.prototype = {
spacing : PropTypes.number,
wrap : PropTypes.bool,
directio : PropTypes.oneOf(["row","column"])
}
export default Stack;
Stack.stories 생성
우선 아래와 같이 코드를 작성했습니다
import Stack from "../components/Stack";
//실제 스토리 객체
export default {
title : "Components/Stack",
component : Stack,
argTypes:{
numberOfChildren : {type : "number",defaultValue : 4}
}
}
Button stories를 만들 때와 동일합니다
스토리에 객체에 제목과, 적용할 컴포넌트를 명시를 합니다
이때 이번에는 argTypes에 액션이 아니라 numberOfChildren이라는 변수를 지정했습니다
이 numberOfChidren은 스토리북에서 입력할 div의 개수를 명시하였습니다
이후 템플릿을 생성을 하는데 이 템플릿 같은 경우는 위에서 지정한 numberOfChidren 만큼 map을 돌려서
<stack></stack> 태그 안에 div를 생성하는 템플릿입니다
const Template = ({numberOfChildren,...args}) => (
<Stack {...args}>
{[...Array(numberOfChildren).keys()].map(n => (
<div style={{width : "50px", height : "50px",backgroundColor:"red",display:"flex",justifyContent:"center",alignItems:"center"}}>
{n + 1}
</div>
))}
</Stack>
)
이렇게 된다면 numberOfChidren 만큼 div가 생성이 되고
stack 컴포넌트에 chidren props 를통하여 <stack></stack> 태그 안에 있는 모든 내용이 전달됩니다
이 이후에는 비슷합니다 bind객체를 생성하고 해당 객체에 원하는 args를 전달해주면 됩니다
export const Horizontal = Template.bind({})
Horizontal.args = {
direction : "row",
spacing : 2,
wrap : false
}
export const Vertical = Template.bind({})
Vertical.args = {
direction : "column",
spacing : 2,
wrap : false
}
export const NoSpacing = Template.bind({})
NoSpacing.args = {
direction : "row",
spacing : 0,
wrap : false
}
export const WrapOverflow = Template.bind({})
WrapOverflow.args = {
numberOfChildren:40,
direction : "row",
spacing : 2,
wrap : true
}
export const Empty = Template.bind({})
Empty.args = {
numberOfChildren:0,
direction : "row",
spacing : 0,
wrap : false
}
여기까지 작성한 후에 스토리북 화면을 보게 되면 stack이라는 폴더가 하나 생성이 되어있으며
numberOfChidren의 값을 변경하면 div의 개수가 달라지는 것을 확인할 수 있습니다
여기까지 해서 스토리북에 대해 알아보았습니다
이 프로젝트는 간단한 예제들로 구성이 되어있는 프로젝트이지만
스토리북 홈페이지에 들어가 보시면 다양한 기업의 스토리북을 확인하실수 있습니다
'React' 카테고리의 다른 글
React CI/CD 구축 해보기 2(EC2 + Github Actions + CodeDeploy) (0) | 2023.03.22 |
---|---|
React CI/CD 구축 해보기 1(EC2+Github Actions + CodeDeploy) (0) | 2023.03.19 |
리액트 디자인 패턴 알아보기 (0) | 2023.01.16 |
React StoryBook 배포 해보기 (0) | 2023.01.09 |
React Recoil 알아보기 (0) | 2023.01.01 |