[React] 프로젝트에서의 Emotion 사용

김민서·2023년 10월 27일

밸런스 게임 개발

목록 보기
2/3

공식 문서

React 스타일 라이브러리는 항상 Styled components만 사용했었는데 이번 토이 프로젝트를 기회로 다른 스타일 라이브러리인 Emotion을 사용해 보기로 했다.

해당 프로젝트는 React 프레임워크를 사용해 만들어졌기 때문에 이에 권장되는 @emotion/react 패키지를 설치하여 사용했다. 다음은 해당 프로젝트에서 내가 한 번씩 사용해 본 기능들을 정리해보았다.

1. Composition

Emotion에서는 따로 선언된 스타일 블록들을 합쳐서 함께 스타일을 구성할 수 있다. 예를 들어 이렇게 base 라는 객체를 선언한 뒤, jsx에서 스타일을 지정할 때 이를 함께 넣어줄 수 있다.
중요한 것은 원래 css에서도 여러 클래스를 사용하여 스타일을 함께 구성할 수 있지만, 가장 나중에 선언된 스타일이 그 앞선 스타일들을 덮어씌우므로 !important를 쓰거나 필요할 때마다 스타일을 재선언할 수 밖에 없다. (보통 !important의 사용은 기피된다.)
Emotion에서는 Composition을 통해 스타일을 적용하는 순서대로 스타일이 병합되기 때문에 스타일이 선언된 순서를 생각할 필요가 없다. !important를 쓰거나 스타일을 재선언할 필요가 없다.

import { css } from '@emotion/react'

const base = css`
  color: hotpink;
`

render(
  <div
    css={css`
      ${base};
      background-color: #eee;
    `}
  >
    This is hotpink.
  </div>
)

실제 사용된 코드. 이렇게 배열 형태로 병합할 수 있다.

  const progress = css`
    height: 100%;
    background: ${theme.palette.blue};
    transition-duration: 0.5s;
  `;

// 생략

   <div css={[progress, { width: `${(100 * (count + 1)) / 11}%` }]} />

2. Theming

Themeing은 @emotion/react 패키지에 포함되어 있다. 위에 Composition을 설명하면서 작성한 코드에 theme.palette.blue를 설명할 차례다.
작은 토이 프로젝트이지만 프로젝트에서 사용되는 색상들을 한 곳에서 관리하고 싶어서 이를 사용하게 되었다.

먼저 styles 폴더 안에 theme.js 파일을 다음과 같이 작성한다.

const palette = {
  black: "rbg(75, 85, 99)",
  gray: "rgb(107,114,128)",
  lightgray: "rgb(209, 213, 219)",
  blue: "rgb(42, 77, 208)",
};

const theme = {
  palette
};

export default theme;

그리고 프로젝트 최상단에 위치한 root.jsx 파일의 jsx를 ThemeProvider로 감싸고 앞서 작성한 theme.js 파일을 적용시켜준다.


import { ThemeProvider } from "@emotion/react";
import theme from "./styles/theme";
return (
	<ThemeProvider theme={theme}>
    // ...
    	<Outlet />
  	// ...
    </ThemeProvider>
);

그러면 하위 파일들은 이 theme을 활용하여 스타일을 적용시킬 수 있게 된다. 하위 파일에서 theme은 useTheme 훅을 사용하여 가져올 수 있다.

const theme = useTheme();

const progress = css`
  height: 100%;
  background: ${theme.palette.blue};
  transition-duration: 0.5s;
`;

3. Media Query - facepaint

Emotion에서 미디어 쿼리를 사용하는 것은 일반 css에서 사용하는 것과 비슷하다. 프로젝트의 최상단에 위치한 root.jsx 파일에 다음과 같이 브레이크 포인트를 설정하고 이를 jsx에 적용시킨다.

const breakpoints = [0, 640, 1140];
const mq = breakpoints.map((bp) => `@media (min-width: ${bp}px)`);

return (
   		// ...
        <div
          css={
            {
              [mq[0]]: { fontSize: "18px" },
              [mq[1]]: { fontSize: "22px" },
            },
          }
        >
          <Outlet />
        // ...
        </div>
  ); 

이 때 facepaint 라이브러리를 설치하면 미디어쿼리를 간편하게 쓸 수 있다.

const breakpoints = [0, 640, 1140];
const mq = facepaint(breakpoints.map((bp) => `@media (min-width: ${bp}px)`));

return (
  		// ...
        <div
          css={
            mq({
  			  fontsize: ["18px", "22px"]
            }),
          }
        >
          <Outlet />
        // ...
        </div>
  ); 

4. Keyframes

Keyframes는 @emotion/react 패키지에 포함되어 있다. Emotion에서 Keyframes를 사용하는 것은 일반 css에서 사용하는 것과 비슷하다.
loading spinner를 구현하기 위해 다음과 같이 작성하였다.


import { css, keyframes } from "@emotion/react";

function LoadingSpinner() {
  const spin = keyframes`
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
    `;
  const loader = css`
    border: 16px solid #f3f3f3;
    border-top: 16px solid #3498db;
    border-radius: 50%;
    width: 50px;
    height: 50px;
    animation: ${spin} 2s linear infinite;
  `;
  return <div css={loader} />;
}

return (
  <LoadingSpinner />
 );

0개의 댓글