styled-components는 리액트에서 사용되는 대표적인 CSS in JS 라이브러리다. 어쩌고 저쩌고..
이런 쓸데없는 설명은 여기저기 써있으니 패스하고 내가 styled-components를 사용하게 된 계기는 다음과 같다.
( 어제 처음 써봄 ㅎ )
1. 클래스명 짓기가 귀찮다. BEM 규칙에 따라 지으면 되지만 그것도 귀찮다.
2. styled-components를 사용하다가 scss or css로 전환하는 건 러닝커브가 없으나 scss or css를 사용하다가 styled-components를 사용하면 러닝커브가 존재한다. 미리미리 대비해 놓으면 나중에 더 편하지 않을까?
3. 모듈식 개발을 하면 css 파일 여기저기 돌아다니며 수정해줘야 하는데 너무 귀찮다.
'귀찮다'라는 말이 두번이나 등장했으면 반드시 다른 방법을 생각해야 한다는 게 나의 지론이기 때문에 바로 styled-components로 넘어와버렸다.
일단 먼저 설치하고 import부터 해보자.
yarn add styled-components
npm install styled-components
택 1하면 된다.
// 1. styled-components를 적용할 모든 컴포넌트에 필수적으로 import해야함.
import styled from "styled-components";
// 2. index.js or App.js 중 한 곳에 import (GlobalStyle보다 상위에 위치해야함)
import { ThemeProvider } from "styled-components";
// 3. global setting 변수를 만들 js 파일을 생성한 뒤 import
import { createGlobalStyle } from "styled-components";
두 번 설명하기 귀찮아서 한 번에 다 적어버림. 각각 파일에 import해주자.
1. 기본 사용법은 다음과 같다. ( + motion framer 적용하기 )
안에 있는 Clock이랑 Focus는 일단 무시하자.. 이것들도 모두 styled components로 만든 것이다.
해당 MainItems 컴포넌트 전체를 감싸는 styled-components 박스를 생성하고 싶다면 어떻게 해야할까?
변수를 생성한 뒤 styled.div(원하는 태그명 무엇으로든 대체 가능)을 입력하고 ``(백틱)안에 원하는 설정을 입력해주면 된다.
nesting도 지원하기 때문에 아주 편리하다. props는 theme에서 다시 알아보자.
박스를 만들었으면 이렇게 감싸주기만 하면 끝이다.
밑에 initail, animate, exit는 motion-framer와 관련된 것인데 궁금하면 아래 글을 읽어봅시다. https://7357.tistory.com/47
아무튼 원래 moition framer는 <div.motion> ... </div.motion>이런 식으로 애니메이션을 적용해줄 태그를 감싸게 만들어줘야 하는데 styled components로 생성한 태그에는 저렇게 만들 수가 없다. 해결책은 다음과 같다.
return (
<Container
as = { motion.div }
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<MainItems userId={userID} />
</Container>
);
// or
const Container = styled(motion.div)`
position: relative;
display: flex;
width: 100vw;
height: 100vh;
justify-content: center;
align-items: center;
// (... 생략)
as를 이용해서 motion.div로 인식하게 해주던지, 혹은 애초에 styled로 변수를 생성할 때 그냥 div가 아니라 motion.div로 만들어주면 된다.
2. global setting
모든 컴포넌트에서 전역으로 사용할 설정은 global setting에 정의해놓으면 편하다.
예를 들어 스크롤바를 없엔다던지, body margin이라던지 등등..
깔끔하게 정리하고 싶으면 아무래도 global style만을 정의할 파일을 하나 새로 만드는 것이 좋겠다.
나는 globalSetting.js라는 파일을 만들어서 정의했다.
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
( .. 원하는 전역 설정 )
`
export default GlobalStyle;
이런 식으로 만들면 된다.
나는 일단 이런 식으로 정의해뒀다.
원하는 전역 설정을 마쳤으면 App.js 혹은 index.js로 가자.
import GlobalStyle from "님이 만든 경로";
function App() {
const location = useLocation();
return (
<div className="App">
<ThemeProvider theme={theme}>
<GlobalStyle />
<AnimatePresence>
<Routes location={location} key={location.pathname}>
<Route path="/" exact element={<LoginPage />} />
<Route path="/main" element={<MainPage />} />
</Routes>
</AnimatePresence>
</ThemeProvider>
</div>
);
}
이렇게 내가 만든 모든 컴포넌트의 상위에 위치하게 해주면 끝. 더이상 손댈 것이 없다. 아주 편리하다.
3. 마지막으로 ThemeProvider !
css에서 root를 설정하거나 scss에서 $로 변수를 미리 지정해놓고 사용하는 것과 마찬가지로 변수에 미리 값을 할당해놓고 사용하기 위해 ThemeProvider를 사용한다.
사실 나처럼 자그마한 것만 만들고 있는 사람한테 그다지 유의미한 것은 아니지만 장기적으로 봤을 때 미리 습관을 들이는 것이 좋을 것이라 판단해서 이제는 미리 설정해놓고 사용하는 것에 적응해보려고 한다.
우선 theme.js 파일을 만들고 원하는 값들을 변수로 설정한다.
const calcRem = (size) => `${size / 16}rem`;
const fontSize = {
xsmall: calcRem(14),
small: calcRem(16),
base: calcRem(18),
large: calcRem(20),
xlarge: calcRem(22),
xxlarge: calcRem(24),
subtitle: calcRem(30),
title: calcRem(58),
clock: calcRem(110),
};
const space = {
xsmall: calcRem(8),
small: calcRem(10),
base: calcRem(12),
large: calcRem(16),
xlarge: calcRem(18),
xxlarge: calcRem(20),
};
const color = {
white: "#FFFFFF",
};
const theme = { fontSize, space, color };
export default theme;
나는 이런 식으로 했으나 다들 본인이 필요한 설정으로 만들면 될 것이다.
중요한 건 마지막에 theme에 모든 변수를 모으고 export해주면 끝.
import { ThemeProvider } from "styled-components";
import theme from "./theme.js";
function App() {
const location = useLocation();
return (
<div className="App">
<ThemeProvider theme={theme}>
<GlobalStyle />
<AnimatePresence>
<Routes location={location} key={location.pathname}>
<Route path="/" exact element={<LoginPage />} />
<Route path="/main" element={<MainPage />} />
</Routes>
</AnimatePresence>
</ThemeProvider>
</div>
);
)
ThemeProvider를 import해준 위치에 방금 만든 변수 theme를 import해주고 ThemeProvider를 최상단에 위치시킨 뒤, theme을 전달해주면 된다.
useState를 사용할 때 많이 본 활용법이다. 마찬가지로 이렇게 보내준 theme은 props로 활용할 수 있다.
p {
font-size: ${(props) => props.theme.fontSize.title};
font-weight: bold;
margin-bottom: ${(props) => props.theme.space.base};
}
이런 식으로.. 전혀 새로울 것 없이 props 사용하던 문법 그대로 활용하면 된다.
일단 찾아보니어쩌고 저쩌고 아직 더 많은 활용법이 존재하는데
나는 미리 모두 완벽하게 배운 뒤 활용하는 것보다 필요하면 찾아서 쓰는 게 좋아서 더 이상 공부하진 않았다.