Styled-Components 이해하기

장동균·2022년 2월 13일
2

styled-components를 사용하면서 새롭게 알게된 점들을 정리한다.


styled-components는 className 기반이다.

개발자 도구에서 확인할 수 있듯이 styled-component는 하나의 유니크한 className에 적용된다.

이를 더 확실하게 확인하기 위해 styled-components를 위한 플러그인을 babel에 추가한다.


App 컴포넌트(리액트 컴포넌트)의 Wrapper 컴포넌트(styled-component)에 유니크한 className WspdT가 적용된 것을 확인할 수 있다,


리액트 컴포넌트 혹은 서드 파티 라이브러리가 제공하는 컴포넌트에 styled-component 적용하기

The styled method works perfectly on all of your own or any third-party components as well, as long as they pass the className prop to their rendered sub-components, which should pass it too, and so on. Ultimately, the className must be passed down the line to an actual DOM node for the styling to take any effect.

공식문서에 의하면 서드 파티 라이브러리가 제공하는 컴포넌트에 styled-components를 적용하기 위해서는 className을 넘겨야한다는 점을 명시하고 있다. 이는 styled-components의 동작 방식이 className을 기반으로 하고 있기 때문이다. className을 넘기지 않는다면 styled-components가 적용될 수 없다.

Input이라는 공통컴포넌트를 만든다고 가정한다. 간단히 다음과 같은 코드로 작성해볼 수 있을 것이다.

// src/components/commons/Input.jsx

import React from 'react'
import styled from 'styled-components'

const Wrapper = styled.div`
	width: 200px;
	height: 100px;
`

export default function Input() {
	return (
    	<Wrapper>
      		<input />
      	</Wrapper>
    )
}

다음 코드의 StyledInput 높이는 300px이 되었을까?

// src/components/Login.jsx

import React from 'react'
import styled from 'styled-components'
import Input from '../commons/Input'

const StyledInput = styled(Input)`
	width: 300px;
`

export default function Login() {
	return (
    	<StyledInput />
    )
}

실제 결과를 확인하면 StyledInput 컴포넌트는 Input 컴포넌트와 완전히 동일한 형태인 width: 200px; height: 100px;의 상태로 유지되고 있음을 확인할 수 있다.

styled-components가 className을 기반으로 동작한다는 사실을 이해하고 있다면 이는 당연한 결과임을 알 수 있다.

`width: 300px`;

해당 코드에 의해 유니크한 className이 생성되고, 이곳에 width는 300px이라는 값이 저장된다.

styled(Input)

생성된 유니크한 className이 Input 컴포넌트의 인자로 넘어간다.

const StyledInput =

Input 컴포넌트가 반환한 값을 받는다.

만든 Input 컴포넌트에서 인자로 넘어오는 className에 대한 처리를 해주지 않았기 때문에 width: 300px이라는 값은 무시된 채 기존의 Input 컴포넌트가 그대로 반환되는 것이다. 때문에 우리는 Input 컴포넌트에서 className을 처리할 수 있는 형태로 수정해야 한다.

// src/components/commons/Input.jsx

import React from 'react'
import styled from 'styled-components'

const Wrapper = styled.div`
	width: 200px;
	height: 100px;
`

export default function Input({className}) {
	return (
    	<Wrapper className={className}>
      		<input />
      	</Wrapper>
    )
}

styled-components에서 &과 >의 기능

&의 경우 해당 컴포넌트 자신의 className을 가리킨다.
>의 경우 해당 컴포넌트의 자식들의 className 가리킨다.
이를 활용하여 다음의 코드를 이해하고 수정해 볼 수 있습니다.

> * {
    &:last-child {
    	border-left: 1px solid #d9dbe9;
	    border-radius: 0 11px 11px 0;
    	width: 160px;
    }
}
  1. 자식 컴포넌트 전체를 선택한다. (> *)
  2. 자기 자신(&, 자식 컴포넌트 전체) 중 마지막 요소(last-child)에 해당 CSS를 적용한다.
> :last-child {
    border-left: 1px solid #d9dbe9;
    border-radius: 0 11px 11px 0;
    width: 160px;
}
  1. 자식 컴포넌트(>) 중 마지막 요소(last-child)를 선택해 CSS를 적용한다.

이렇게 &, >가 styled-components에서 가지는 기능을 이해해야만 불필요한 코드를 제거할 수 있다.


변수 사용하기

const Wrapper = styled.div`
	width: 12px;
	height: 12px;
	border-radius: 12px;
`

styled-component를 사용하다보면 이렇게 똑같은 값이 반복되는 경우들이 생긴다. 이런 경우 변수를 활용하면 훨씬 더 쉽게 코드를 작성할 수 있다.

const Wrapper = styled.div`
	--size: 12px;
    width: var(--size);
    height: var(--size);
    border-radius: var(--size);
`

styled-component에서 변수를 만들 때는 --를, 변수를 사용할 때는 var(--변수명)을 사용한다.

하지만, 이렇게 특정한 컴포넌트 내부에서만 반복되는 것이 아닌 여러 컴포넌트에서 반복되는 값들이 존재할 수 있다. 이런 경우 변수를 전역에 두고 싶다는 생각이 든다. 해당 니즈에 대한 구현은 다음과 같다.

import { createGlobalStyle } from "styled-components"

const GlobalStyle = createGlobalStyle`
  :root {
    --theme-primary: #F5005E;
  }
`;

const StyledApp = styled.div`
  color: var(--theme-primary);
`;

function App() {
  return (
    <StyledApp>
      <GlobalStyle />
    </StyledApp>
  );
}

다음과 같이 createGlobalStyle :root에 작성한 값은 전역에서 참조가 가능하다.

createGlobalStyle을 활용하여 다크모드를 구현할 수도 있다. 이곳을 참조하면 된다.


참고문헌

https://github.com/styled-components/styled-components/issues/2314
https://stackoverflow.com/questions/52542817/styled-components-not-applying-style-to-custom-functional-react-component
https://cheri.tistory.com/159
https://daily.dev/blog/theming-styled-components-with-css-custom-properties

profile
프론트 개발자가 되고 싶어요

0개의 댓글