컴포넌트 중심으로 UI를 개발하는 방법론에 대해 알아보자.
컴포넌트
단위부터 시작해서 UI view를 구성하기 위해 점진적으로 조립해가는 상향적(bottom-up) 특징을 가지고 있다.프로젝트 초기부터 UI 컴포넌트를 중심으로
<Button ... />
<Modal ... />
<Chart ... />
와 같이 개발하여 아래의 이점들을 얻기 위함이다.
Component Driven Development, CDD
를 지원하는 UI 컴포넌트 익스플러어 툴.
Storybook은 기본적으로 독립적인 개발환경에서 실행된다.
개발자는 애플리케이션의 다양한 상황에 구애받지 않고 UI 컴포넌트를 집중적으로 개발할 수 있다.
Stories
로 저장리액트에서 컴포넌트를 스타일링 할 때 가장 기본적인 방법은 css파일을 만들어 컴포넌트에서 import 해서 사용하는 것이다.
이 방법도 충분히 편리할 수 있지만, 더 편하게 쉽게 작업할 수 있는 방법을 알아보자.
Sass
: Syntactically Awesome Style Sheets ; 문법적으로 완전 멋진 스타일 시트.
Sass
는 CSS pre-processor로서, 복잡한 작업을 쉽게 할 수 있게 도와주고, 코드의 재활용성을 높여준다.
또한, 코드의 가독성을 높여주어 유지보수를 쉽게 해준다.
Sass
에서는 두가지의 확장자(.scss
/ .sass
)를 지원한다.
$font-stack: Helvetica, sans-serif
$primary-color: #eaeaea
body
font: 100% $font-stack
color: $primary-color
$font-stack: Helvetica, sans-serif;
$primary-color: #eaeaea;
body {
font: 100% $font-stack;
color: $primary-color;
}
$blue: #228be6; // 변수 선언
.Button {
display: inline-flex;
color: white;
cursor: pointer;
background: $blue; // 사용
&:hover {
background: lighten($blue, 10%); // 색상 10% 밝게
}
&:active {
background: darken($blue, 10%); // 색상 10% 어둡게
}
}
더 많은 차이점은 여기에서 확인하자.
보통 scss 문법이 더 많이 사용된다.
리액트 프로젝트에서 컴포넌트를 스타일링 할 때, CSS Module을 사용하면 CSS 클래스가 중첩되는 것을 완벽하게 방지할 수 있다.
레거시 프로젝트에 리액트를 도입하게 될 경우,
또는 클래스 이름 짓는 규칙을 정하기 힘든 상황이거나 번거로울 때 사용하면 좋다 !
CSS 네이밍 규칙을 만들고 따르기 싫다면, CSS Module을 사용하자..
Box.module.css
.Box {
background: lightgray;
padding: 2rem;
}
Box.js
import React from 'react';
import styles from './Box.module.css';
function Box() {
return <div className={styles.Box}>{styles.Box}</div>;
}
export default Box;
className
을 설정 할 때에는 styles.Box
처럼 import로 불러온 styles
객체 안에 있는 값을 참조해줘야 한다.
Styled-Component
는 현존하는 CSS in JS 관련 리액트 라이브러리 중에서 가장 인기 있는 라이브러리.# with npm
$ npm install --save styled-components
styled-component
를 사용하기 전에, Tagged Template Literal
문법에 대해 짚고 넘어가면 styled-component가 내부적으로 어떻게 작동하는지 이해할 수 있다.
일단, Template Literal에 대해서는 익숙할 것이다.
const name = 'yezo';
const message = `hello ${name}`;
console.log(message); // "hello yezo"
만약, Template Literal을 사용할 때 ${}
안에 문자열, 숫자가 아닌 객체를 넣는다면 어떻게 될까 ?
const obj = { a: 1 };
const message = `${odj}`;
console.log(message); // "[object Object]"
함수를 넣는다면 어떻게 될까 ?
const fn = () => true;
const message = `${fn}`;
console.log(message); // "() => true"
Template Literal을 사용하면서, 그 내부에 넣은 자바스크립트 값을 조회하고 싶을 땐 Tagged Template Literal 문법을 사용할 수 있다.
const red = '빨강'
const blue = '파랑'
function favoriteColor(texts, ...values) {
console.log(texts);
console.log(values);
}
favoriteColors`내가 좋아하는 색은 ${red}과 ${blue}이다.`
// (3) ["내가 좋아하는 색은 ", "과 ", "이다.", raw: Array(3)]
// (2) ["빨강", "파랑"]
styled-component
에서는 스타일 속성을 가진 컴포넌트를 정의할 때 함수를 전달하고 그 함수 안에서 props를 읽어오기도 한다.
const styleDiv = styled`
background: ${props => props.color};
`;
import React from 'react'
import styled from 'styled-component'
const Circle = styled.div`
width: 5rem;
height: 5rem;
background: ${props => props.color || 'black'};
border-radius: 50%;
`;
function App() {
return <Circle color='blue' />;
}
export default App;
// Button component
...
background: ${props => props.primary ? 'palevioletred' : 'white'};
color: ${props => props.primary ? 'white' : 'palevioletred'};
...
// App component
...
<Button>Normal</Button>
<Button primary>Primary</Button>
같은 스타일 속성을 지닌 여러 개의 컴포넌트들 중에 몇 개의 컴포넌트에는 변화를 주고 싶은 경우, 상속받고자 하는 스타일 속성을 지닌 컴포넌트를 styled()
로 감싼 뒤 변경하고 싶은 속성만 새로 정의해준다.
기존 속성을 확장해서 사용 가능하다.
// 기존의 Button 컴포넌트에서 Tomato 컴포넌트만을 위한 새로운 속성을 추가.
const Tomato = styled(Button)`
color: tomato;
border-color: tomato;
`;
styled-component
는 중첩 스타일링을 위해 scss와 같은 전처리 기능을 자동으로 지원하며 ampersnad(&)
기호를 사용한다.ampersnad(&)
를 사용하지 않으면 그냥 후손 셀렉터처럼 동작.ampersnad(&)
기호는 컴포넌트 안에서 적용되는 CSS규칙을 확장해 줌으로써 순수 CSS
와 styled-component
를 혼용해야 하는 경우에 각 스타일 간의 충돌을 피하는 데에 유용하다.styled-component
의 정의는 render
메서드 밖에 정의한다.const Thing = styled.div`
color: blue;
&:hover {
color: red; // <Thing> when hovered
}
& ~ & {
background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it
}
& + & {
background: lime; // <Thing> next to <Thing>
}
&.apple {
background: orange; // <Thing> tagged with an additional CSS class ".apple"
}
.banana & {
border: 1px solid; // <Thing> inside another element labeled ".banana"
}
.blueberry {
background-color: yellow; // an element labeled ".blueberry" inside <Thing> without ampersand(&)
}
`;