Component Driven Development (CDD)
Component Driven Development는 디자인과 개발 단계에서부터 재사용할 수 있는 UI 컴포넌트를 부품단위로 만들어 나가는 개발방법을 의미한다. 페이지 전체에 적용될 수 있는 작은 요소들(버튼, 토글, 모달 등)을 사전에 먼저 컴포넌트화 하여 해당 요소가 필요할 때 재사용하고, 이런 컴포넌트들이 모여 페이지를 완성하는 상향식 개발이다.
Styled Components
Styled Components는 앞서 말했듯 CSS를 컴포넌트 영역으로 불러들이기 위한 CSS-in-JS 중 하나로, 컴포넌트부터 상향식으로 제작하는 CDD를 위한 라이브러리이기도 하다. CSS를 컴포넌트화 시킴으로써 기존 CSS가 가진 불편함(class, id 이름을 짓는 문제나 CSS 파일이 너무 길어지는 등)을 해결시켜준다. CSS-in-JS 라이브러리인 Styled Components를 사용하게 되면 CSS도 쉽게 Javascript 안에 넣어줄 수 있기 때문에 HTML + JS + CSS까지 묶어서 하나의 JS파일 안에서 컴포넌트 단위로 개발할 수 있게 된다.
Styled Components 설치
터미널에서 npm이나 yarn을 이용해 라이브러리를 설치한다.
# with npm
$ npm install --save styled-components
# with yarn
$ yarn add styled-components
Styled Components는 package.json에 다음 코드를 추가하도록 권장하고 있다. 아래의 코드를 추가하면 여러 버전의 Styled Components가 설치되어 발생하는 문제를 줄여준다.
{
"resolutions": {
"styled-components": "^5"
}
}
Styled Components 문법
컴포넌트 만들기
Styled Components는 ES6의 템플릿 리터럴 문법(``
)을 사용한다. 컴포넌트를 선언한 후 styled.TAG
를 할당하고, 백틱 안에 기존 CSS 작성 문법과 동일하게 스타일 속성을 작성한 뒤 React 컴포넌트를 사용하듯 리턴문 안에 작성해주면 스타일이 적용된 컴포넌트가 렌더된다.
만약 해당 컴포넌트에 의사선택자(:hover
등)을 사용하고 싶다면 &
을 활용하여 작성할 수 있다. &
은 해당 컴포넌트를 재참조한다는 뜻이다.
import styled from "styled-components";
// Styled Components로 컴포넌트를 만들고
const BlueButton = styled.button`
background-color: blue;
color: white;
/* 의사선택자 사용 */
&:hover{
background-color: white;
}
`;
export default function App() {
// React 컴포넌트를 사용하듯이 사용
return <BlueButton>Blue Button</BlueButton>;
}
컴포넌트 재활용
이미 만들어진 컴포넌트를 재활용해 새로운 컴포넌트를 만들 수도 있다. 컴포넌트를 선언하고 styled()
에 재활용할 컴포넌트를 전달인자로 넣고 추가하고 싶은 스타일 속성을 백틱 안에 작성해주면 된다.
import styled from "styled-components";
const BlueButton = styled.button`
background-color: blue;
color: white;
`;
// 만들어진 컴포넌트를 재활용해 컴포넌트 생성
const BigBlueButton = styled(BlueButton)`
padding: 10px;
margin-top: 10px;
`;
// 재활용한 컴포넌트를 재활용도 가능
const BigRedButton = styled(BigBlueButton)`
background-color: red;
`;
export default function App() {
return (
<>
<BlueButton>Blue Button</BlueButton>
<br />
<BigBlueButton>Big Blue Button</BigBlueButton>
<br />
<BigRedButton>Big Red Button</BigRedButton>
</>
);
}
Props 활용
Styled Components로 만든 컴포넌트도 React 컴포넌트처럼 props를 내려줄 수 있다. 내려준 props 값에 따라 컴포넌트를 렌더링 하는 것도 가능하다. 백틱 내에 템플릿 리터럴 문법(${}
)을 사용하여 JavaScript 코드를 사용할 수 있고, props를 받아오려면 props를 인자로 받는 함수를 만들어 사용하면 된다.
Props로 조건부 렌더링하기
위 코드는 삼항연산자를 활용해 <Button>
컴포넌트에 skyblue
라는 props가 있는지 확인하고, 있으면 배경색으로 skyblue
를, 없을 경우 white
를 지정해주는 코드이다. 이 코드에 따라 렌더링 된 <button>
컴포넌트는 아래 그림과 같다.
Button1의 경우 skyblue
라는 props가 있어 배경색이 skyblue
로 지정되었고, Button2는 props가 없기 때문에 배경색이 white
로 지정된 것을 볼 수 있다.
import styled from "styled-components";
import GlobalStyle from "./GlobalStyle";
// 받아온 prop에 따라 조건부 렌더링 가능
const Button1 = styled.button`
background: ${(props) => (props.skyblue ? "skyblue" : "white")};
`;
export default function App() {
return (
<>
<GlobalStyle />
<Button1>Button1</Button1>
<Button1 skyblue>Button1</Button1>
</>
);
}
Props 값으로 렌더링하기
props의 값을 통째로 활용해 컴포넌트 렌더링에 활용할 수 있다.
삼항연산자를 사용하고, props.color가 없다면 white를, props.color가 있다면 그 값을 그대로 배경색으로 리턴하여 적용되게끔 하는 것을 볼 수 있다. props를 활용한 스타일 지정은 꼭 삼항연산자만 활용할 수 있는 것이 아닌, JavaScript 코드라면 무엇이든 사용할 수 있기 때문에 다양하게 활용 가능하다.
import styled from "styled-components";
import GlobalStyle from "./GlobalStyle";
// 받아온 prop 값을 그대로 이용해 렌더링
const Button1 = styled.button`
background: ${(props) => (props.color ? props.color : "white")};
`;
// 간략 계산법을 활용
const Button2 = styled.button`
background: ${(props) => props.color || "white"};
`;
export default function App() {
return (
<>
<GlobalStyle />
<Button1>Button1</Button1>
<Button1 color="orange">Button1</Button1>
<Button1 color="tomato">Button1</Button1>
<br />
<Button2>Button2</Button2>
<Button2 color="pink">Button2</Button2>
<Button2 color="turquoise">Button2</Button2>
</>
);
}
전역 스타일 설정
전역에 스타일을 설정을 할 수 있게 Styled Components는 이를 위한 컴포넌트도 준비해두었다. 우선 전역 스타일 설정을 위해 Styled Components에서 createGlobalStyle
을 불러온 뒤, 해당 함수를 사용해 일반적인 컴포넌트와 같은 형식으로 작성해 생성한다. 생성된 전역 스타일 컴포넌트는 최상위 컴포넌트에서 사용해주면 전역 스타일 컴포넌트가 적용된다.
// createGlobalStyle 함수 불러오기
import { createGlobalStyle } from "styled-components";
// 전역 스타일을 위한 컴포넌트 생성
const GlobalStyle = createGlobalStyle`
button {
padding : 5px;
margin : 2px;
border-radius : 5px;
}
`
function App() {
return (
<>
{// 전역 스타일 컴포넌트 적용}
<GlobalStyle />
<Button>전역 스타일 적용하기</Button>
</>
);
}
Storybook
Storybook은 CDD를 지원하는 도구 중 하나인 Component Explorer(컴포넌트 탐색기)에 속하는 UI 개발 도구로 각각의 컴포넌트들을 따로 볼 수 있게 구성해주어 한 번에 하나의 컴포넌트에서 작업할 수 있다. 복잡한 개발 스택을 시작하거나, 특정 데이터를 데이터베이스로 강제 이동하거나, 어플리케이션을 탐색할 필요 없이 전체 UI를 한 눈에 보고 개발할 수 있다.
Storybook은 재사용성을 확대하기 위해 컴포넌트를 문서화하고, 자동으로 컴포넌트를 시각화하여 시뮬레이션 할 수 있는 다양한 테스트 상태를 확인할 수 있어 이를 통해 버그를 사전에 방지할 수 있게 도와준다. 테스트 및 개발 속도를 향상시키는 장점이 있으며, 어플리케이션 또한 의존성을 걱정하지 않고 빌드할 수 있다.
Storybook에서 지원하는 주요 기능
- UI 컴포넌트들을 카탈로그화하기
- 컴포넌트 변화를 Stories로 저장하기
- 핫 모듈 재 로딩과 같은 개발 툴 경험을 제공하기
- 리액트를 포함한 다양한 뷰 레이어 지원하기
Storybook 설치
프론트엔드 라이브러리(React 등) 설치 후, 아래의 명령어를 입력한다. 이 명령어는 package.json
을 참조하여 프론테엔드 라이브러리에 맞는 Storybook 사용 환경을 알아서 만들어주기 때문에, React가 아니더라도 다양한 프론트엔드 라이브러리에서 사용할 수 있다.
npx storybook init
Storybook 기본 사용법
Storybook에서 컴포넌트화된 UI 요소를 미리 확인하기 위해서 컴포넌트를 생성한다. 이 때, Styled Components를 활용해 props를 넣을 수 있다.
import react from 'react'
import styled from 'styled-components'
const StyledButton = styled.button`
background: ${(props) => props.bgColor || "white"};
color: ${(props) => props.color || "black"};
width: ${(props) => props.size === "big" ? "200px" : "100px"};
height: ${(props) => props.size === "big" ? "80px" : "40px"};
`
const Button = ({bgColor, color, size, text}) => <StyledButton bgColor={bgColor} color={color} size={size}>{text}</StyledButton>
export default Button
/.storybook
안에 있는 Storybook 설정 파일에 의해 컴포넌트 파일과 똑같은 파일 이름에 .stories를 붙여 파일을 만들면 알아서 스토리로 인식한다. 같은 위치에 컴포넌트 파일명.stories.js
파일을 생성하고 아래와 같이 작성한다.
// 작성한 컴포넌트를 불러온다
import Button from "./Button";
// 스토리의 기본 속성을 정의
export default {
// 컴포넌트의 이름으로 '/'를 이용해 카테고리화 할 수 있다.
title: "Practice/Button",
// 어떤 컴포넌트를 가져와서 스토리를 만들지 명시한다.
component: Button,
// 컴포넌트 정의에 사용된 전달인자의 속성을 정한다.
// Storybook에서 보게 될 속성의 타입이자 전달인자의 타입
argTypes: {
bgColor: {control: "color"},
color: { control: "color" },
size: { control: { type: "radio", options: ["big", "small"] } },
text: { control: "text" },
}
};
// 전달인자를 Storybook 상에서 직접 받는 스토리
// (컴포넌트의 기본적인 스타일로 이해할 수 있음)
// Storybook에서 확인하고 싶은 컴포넌트 작성 : export const
export const StorybookButton = (args) => {
// 전달인자를 받아 구조 분해 할당으로 props를 내려준다.
return <Button {...args}></Button>;
};
// 위의 컴포넌트를 토대로 사전 설정 역시 가능
// 스토리를 만들기 위한 템플릿
// Title 컴포넌트가 args를 전달받아 props로 내려준다
const Template = (args) => <Button {...args} />
// 템플릿을 사용하여 Storybook에 넣어줄 스토리를 하나 만든다
// Template.bind({}); 는 정해진 문법이라고 생각하고 사용
// (bind 하지 않으면 전달인자를 설정할 수 없음)
export const RedButton = Template.bind({});
// 만들어준 스토리의 전달인자를 작성
RedButton.args= {
bgColor: "red",
color: "white",
size: "big",
text: "Red Button"
}
stories.js 파일을 저장하고 나면 Storybook 상에서 아래와 작성한 컴포넌트를 확인할 수 있다.
Uploaded by N2T