์ปดํฌ๋ํธ ํ์๊ธฐ(Component Explorer)
Component Driven Development๊ฐ ํธ๋ ๋๊ฐ ๋๋ฉด์, ์ด๋ฅผ ์ง์ํ๋ ๋๊ตฌ ์ค ํ๋์ธ Component Explorer๊ฐ ๋ฑ์ฅํ๋ค.
Component Explorer์๋ ๋ง์ UI ๊ฐ๋ฐ ๋๊ตฌ๊ฐ ์๋๋ฐ, ๊ทธ ์ค ํ๋์ธ Storybook์ ๋ํด ์์๋ณด์.
: UI ์ปดํฌ๋ํธ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ฐ๋ฐํ๊ณ , ํ ์คํธ ๋ฐ ๋ฌธ์ํํ ์ ์๋๋ก ๋์์ฃผ๋ ๋๊ตฌ
npx create-react-app ํ๋ก์ ํธ๋ช
npx storybook init
์ด ๋ช ๋ น์ด๋
package.json
์ ๋ณด๊ณ ์ฌ์ฉ ์ค์ธ ํ๋ก ํธ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ง๋ Storybook ํ๊ฒฝ์ ์์์ ๋ง๋ค์ด์ฃผ๊ธฐ ๋๋ฌธ์, React๊ฐ ์๋๋๋ผ๋ ๋ค์ํ ํ๋ก ํธ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Vue.js, Angular ๋ฑ)์์ ์ฌ์ฉํ ์ ์๋ค.
/.storybook
ํด๋์ /src/stories
ํด๋๊ฐ ์์ฑ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค./.storybook
ํด๋ - Storybook ๊ด๋ จ ์ค์ ํ์ผ(config ํ์ผ)/src/stories
ํด๋ - Storybook ์์ ํ์ผpackage.json
์ scripts์ ๋ค์ ์คํฌ๋ฆฝํธ๋ค์ด ์ถ๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.{
"scripts": {
"storybook": "start-storybook -p 6006 -s public",
// localhost:6006์์ Storybook์ ์คํํ๋ค.
"build-storybook": "build-storybook -s public"
}
}
npm run storybook
์ปดํฌ๋ํธ๋ช
.js
ํ์ผsrc
ํด๋ ์์ ์ปดํฌ๋ํธ๋ช
.js
ํ์ผ์ ๋ง๋ค๊ณ , ์์ React ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ์ฌ export ํด์ค๋ค.
ex) ํ์ดํ story๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด Title.js
ํ์ผ์ ์์ฑํ๊ณ , ์์ Title ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋ค.
// Title.js ํ์ผ
import React from "react";
// Title ์ปดํฌ๋ํธ๋ props๋ก textContent์ textColor๋ฅผ ๋ฐ๋๋ค.
const Title = ({textContent, textColor}) => {
return <h1 style={{color: textColor}}>{textContent}</h1>
};
// Title ์ปดํฌ๋ํธ๋ฅผ exportํด์ค๋ค.
export default Title;
์ปดํฌ๋ํธ๋ช
.stories.js
ํ์ผ๊ฐ์ ์์น์ธ src
ํด๋ ์์ ์ปดํฌ๋ํธ๋ช
.stories.js
ํ์ผ์ ๋ง๋ ๋ค.
ex) Title.stories.js
./storybook
ํด๋ ์์ ์๋ Storybook ์ค์ ํ์ผ์ ์ํด์ ์ปดํฌ๋ํธ ํ์ผ๊ณผ ๋๊ฐ์ ํ์ผ ์ด๋ฆ์.stories
๋ฅผ ๋ถ์ฌ ํ์ผ์ ๋ง๋ค๋ฉด ์์์ ์คํ ๋ฆฌ๋ก ์ธ์ํ๋ค.
// Title.stories.js ํ์ผ
// Title.js ํ์ผ์์ Title ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฌ์จ๋ค.
import Title from "./Title";
export default {
title: "Folder1/Title", // '/'๋ฅผ ๋ฃ์ด ์นดํ
๊ณ ๋ฆฌํํ ์ ์๋ค.
component: Title, // ์คํ ๋ฆฌ๋ก ๋ง๋ค ์ปดํฌ๋ํธ๋ฅผ ๋ช
์ํด์ค๋ค.
argTypes: { // ์ปดํฌ๋ํธ์ ํ์ํ ์ ๋ฌ์ธ์(props)์ ํ์
์ ์ ํด์ค๋ค.
textContent: {control: "text"},
textColor: {control: "text"}
}
}
// ์ด ํ
ํ๋ฆฟ์์ args๋ฅผ ์ ๋ฌ ๋ฐ์ Title์ props๋ก ๋ด๋ ค์ค๋ค.
const Template = (args) => {
return <Title {...args} />
}
Storybook์์ ํ์ธํ๊ณ ์ถ์ ์ปดํฌ๋ํธ๋ export const
๋ฅผ ์ด์ฉํด ์์ฑํ๋ค.
ํ
ํ๋ฆฟ์ ์ด์ฉํ๋ฉด Storybook์ ์คํ ๋ฆฌ๋ก ์ถ๊ฐํ ์ ์๋ค.
// Template.bind({})๋ ์ ํด์ง ๋ฌธ๋ฒ์ด๋ผ๊ณ ์๊ฐํ๊ณ ์ฌ์ฉํ๋ฉด ๋๋ค.
export const RedTitle = Template.bind({});
RedTitle.args = {
textContent: "This is Red Title!",
textColor: "red"
}
Folder1 ์ด๋ผ๋ ์นดํ
๊ณ ๋ฆฌ์ Title์ด ๋ด๊ฒจ์ ธ ์๊ณ ,
Title ์์๋ ํ
ํ๋ฆฟ์ ์ฌ์ฉํด ๋ง๋ Red Title์ด๋ผ๋ ์คํ ๋ฆฌ๊ฐ ๋ด๊ฒจ์ ธ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Blue Title์ด๋ผ๋ ์คํ ๋ฆฌ๋ ํ๋ ๋ ์ถ๊ฐํด๋ณด์.
export const BlueTitle = Template.bind({});
BlueTitle.args = {
textContent : "I am Blue Title!",
textColor: "Blue"
}
ํ ํ๋ฆฟ์ ์ฌ์ฉํ์ง ์๊ณ ์ ๋ฌ ์ธ์๋ฅผ ์ง์ ๋ฐ๋๋ก ํ๋ฉด, ์ ๋ฌ ์ธ์๋ฅผ ์ง์ ๋ฐ๋ ์คํ ๋ฆฌ๋ฅผ ๋ง๋ค ์ ์๋ค.
// title.stories.js ํ์ผ
export const PropsTitle = (args) => {
return <Title {...args} />
}
npm install styled-components
์ปดํฌ๋ํธ๋ช
.js
ํ์ผ์ ๋ง๋ ๋ค.// Button.js ํ์ผ
import React from "react";
import styled from 'styled-components';
// Styled Components๋ฅผ ์ด์ฉํด StyledButton ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๋ค.
const StyledButton = styled.button`
background: ${(props) => props.color || "white"};
width: ${(props) => (props.size === "big" ? "200px" : "100px")};
height: ${(props) => (props.size === "big" ? "80px" : "40px")};
`;
// Button ์ปดํฌ๋ํธ๋ ์์์ ์์ฑํ props์ text๋ฅผ ์ ๋ฌ์ธ์๋ก ๋ฐ๋๋ค.
const Button = ({color, size, text}) => (
<StyledButton color={color} size={size}>{text}</StyledButton>
);
// Button ์ปดํฌ๋ํธ๋ฅผ exportํด์ค๋ค.
export default Button;
์ปดํฌ๋ํธ๋ช
.stories.js
ํ์ผ์ ๋ง๋ ๋ค.// Button.stories.js ํ์ผ
// Button.js ํ์ผ์์ Button ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฌ์จ๋ค.
import Button from "./Button";
export default {
title: "Folder2/Button",
component: Button,
argTypes: { // ์ปดํฌ๋ํธ์ ํ์ํ ์ ๋ฌ์ธ์(props)์ ํ์
์ ์ ํด์ค๋ค.
color: { control: 'color'},
size: { control: { type:'radio', options : ['big', 'small'] }},
text: { control: 'text'}
}
};
// ํ
ํ๋ฆฟ์ ์ฌ์ฉํ์ง ์๊ณ ์ ๋ฌ์ธ์๋ฅผ ์ง์ ๋ฐ๋๋ค.
export const StorybookButton = (args) => (
<Button {...args}></Button>
)
์ ๋ฌ์ธ์๋ก ๋ฐ์ color
, size
,text
๋ฅผ ์ง์ ์
๋ ฅํ ์ ์๋ค.