-
styled-componentsFW, Lib 공부/React 2022. 7. 20. 17:09
리액트 프로젝트의 크기가 커질수록, 태그의 양이 많아질수록 점점 더 태그 트리구조를 파악하기 힘들어질 뿐더러, css와 class 이름 붙이기도 힘들어진다.
하지만, styled-components만 있으면 그런걱정 끝!
styled-components - 공식 문서 페이지
Use the best bits of ES6 and CSS to style your apps without stress 💅🏾
...공식 사이트 최상단에 나와있는 문구이다.
그런데, 정말 말대로 스트레스가 확 줄어드는 느낌이다.
기존에 html 태그에 스타일을 지정하려먼 다음의 단계를 거쳐야 했다.
태그 지정 -> 클래스 이름 지정 -> css 파일 생성 및 작성 -> css 파일 연동
하지만, styled-components는 다음의 과정만 있음면 된다.
변수 생성(태그 형식도 함께 지정) -> css 작성 -> 변수 사용
실제로 위 모든 코드는 아래와 같이 짧고 직관적이다.
const Logo = styled.img<{ isSelected: boolean }>` top: ${(props) => (props.isSelected ? "calc(250px - 50vh)" : 0)}; left: ${(props) => (props.isSelected ? "300px" : "100px")}; transform: scale(${(props) => (props.isSelected ? "50%" : "100%")}); transition: top 0.5s cubic-bezier(0.3, 0, 0.2, 1), left 0.5s cubic-bezier(0.7, 0, 0.8, 1), transform 0.5s ease-in-out; will-change: top, left, transfrom; `;
styled component 생성 법
styled component를 생성하는 방법은 크게 두 가지로 나뉜다.
1. 일반적인 생성
const Logo = styled.img<{ key: type }>`...`;
위 경우는 일반적인 생성 방식이다. styled.<html 태그>`<css 문법>`; 을 통해 styled component 태그를 생성한다.
<{ key: type }>부분은 뒤에 설명하겠다.
2. 상속 생성
const SmallLogo = styled(Logo)`...`;
위 경우는 Logo라는 이름의 styled component를 상속받아 생성하는 경우이다.
이 경우 SmallLogo component는 Logo의 속성을 모두 상속받으며, 추가적인 속성도 지정할 수 있다. extend와 같은 원리.
이렇게 생성된 styled components는 JSX 요소로서 마치 태그처럼 사용할 수 있다.
다만, 리액트 프레임워크에서 약속된 규칙에 따라 대문자로 시작해야 한다는 제약이 있기는 하다.
<div> <Logo src={assets[0]} alt="iconImage" isSelected={mainTabIdx !== 0} /> </div>
이렇게 하면 태그의 이름도 직관적이라 div 지옥에서 벗어날 수 있을 뿐만 아니라, css도 한번에 처리할 수 있어서 편하다. 물론 class 이름때문에 스트레스 받을 일도 없다!
사용자 정의 속성
뿐만 아니라, styled components로 생성된 JSX는 인자도 전달할 수 있어, 상태에 따른 동적인 디자인도 구현할 수 있다.
다음 예시를 살펴보자.
const Logo = styled.img<{ isSelected: boolean }>` top: ${(props) => (props.isSelected ? "calc(250px - 50vh)" : 0)}; left: ${(props) => (props.isSelected ? "300px" : "100px")}; transform: scale(${(props) => (props.isSelected ? "50%" : "100%")}); transition: top 0.5s cubic-bezier(0.3, 0, 0.2, 1), left 0.5s cubic-bezier(0.7, 0, 0.8, 1), transform 0.5s ease-in-out; will-change: top, left, transfrom; `; function MainHome({ isLoading, assets }: IHomeInfo) { ... return ( ... <Logo src={assets[0]} alt="iconImage" isSelected={mainTabIdx !== 0} /> ) }
위 코드의 경우, Logo JSX는 img 태그이기 때문에 기본적으로 src, alt 속성을 받을 수 있다.
하지만, 추가로 isSelected라는 사용자 정의 속성도 추가해 줬다.
참고로 <{ isSelected: boolean }> 가 붙은 이유는, typescript에서 타입을 정의해 줄 필요가 있었기 때문이다.
여기서 속성과 타입을 정의해줘야 아래의 JSX에서 사용할 수 있다.
isSelected 속성은 Logo styled component로 전달되는데, 이는 props 속성으로 접근이 가능하다.
css 속성을 정의하는 ``(back-quote) 문자열 안에서 ${}을 통해 js코드를 호출할 수 있는데, 이 때 함수를 넣어주게 되면 함수의 첫 번째 매개변수로 props 객체가 반환된다.
props 객체 안에는 theme을 비롯한 여러 키 값이 존재하는데, 여기에 사용자 정의 속성 isSelected도 존재한다.
따라서 위 코드의 경우에는 ${(props) => (props.isSelected)} 는 true 또는 false값으로 변환되게 된다.
이렇게 하면 동적으로 isSelected 값이 변할 때 마다 다른 값으로 css를 적용할 수 있게되어 상태에 따른 다른 디자인으로 적용할 수 있게된다.
자식 태그 컨트롤
뿐만 아니라22, 하나의 styled component로 여려개의 JSX 태그를 컨트롤 할 수 있다.
다음 예시를 살펴보자.
const Etc = styled.div<{ isSelected: boolean }>` opacity: ${(props) => (props.isSelected ? 0 : 1)}; transition: opacity 0.5s ease-out; & > * { position: absolute; left: 100px; } //Accessing... & > span:nth-child(1) { font-size: 20px; font-weight: 400; margin-left: 30px; top: 160px; } //Projects Archive & > div:nth-child(2), & > div:nth-child(3) { display: flex; font-size: 40px; font-weight: 700; margin-left: 28px; top: 180px; & > h1:last-child { font-weight: 400; margin-left: 10px; } } `;
이렇게 하면 Etc JSX의 자식 태그 span, div, div의 스타일을 같이 지정해 줄 수 있다.
여기서 &는 본인(Etc)를 지칭한다.
더 많은 기능이 많지만, 다 적는건 의미가 없고 찾아보는게 나으므로 사용하면서 소름돋았던 기능 하나만 더 소개해주고 마무리 하겠다.
바로 상속 생성의 연장선으로 framer-motion 라이브러리와의 연동이다.
framer-motion 연동
framer-motion에 대해서는 따로 포스팅 하겠지만, 간단하게 설명하자면, 컴포넌트의 애니메이션을 처리해주는 라이브러리이다.
framer-motion에 styled-components를 적용하는 방법은 다음의 예시 코드를 살펴보자.
const Box = styled(motion.div)<{ bgphoto: string }>` background-color: white; background-image: url(${(props) => props.bgphoto}); background-size: cover; background-position: center center; height: 170px; color: tomato; font-size: 64px; &:first-child { transform-origin: center left; } &:last-child { transform-origin: center right; } `;
보면 styled() 안에 다른 styled component를 넣은게 아닌, framer-motion태그를 넣은 것을 확인할 수 있다.
이렇게 생성된 Box JSX 태그는 framer-motion의 기능을 사용할 수 있을 뿐더러, styled-components의 기능 또한 사용할 수 있게 된다.
정말 놀랍지 아니한가...
요약
const Box = styled(motion.div)<{ bgphoto: string }>` background-color: white; background-image: url(${(props) => props.bgphoto}); background-size: cover; background-position: center center; height: 170px; color: tomato; font-size: 64px; &:first-child { transform-origin: center left; } &:last-child { transform-origin: center right; } `;
'FW, Lib 공부 > React' 카테고리의 다른 글
recoil, recoil-persist (0) 2022.07.20 React 프로젝트 gh-pages 배포 (0) 2022.07.03 useRouteMatch() (0) 2022.06.22 useLocation() (0) 2022.06.22 useParams() (0) 2022.06.22