ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ReactJS] Styled Components (CSS IN JS) 적용 및 사용법 ( 부록 : NextJS + TypesScript 환경 적용 및 사용법 )
    frontend/react&next 2022. 3. 3. 16:30

    웹 프론트엔드 개발 시에 CSS를 적용하는 방식으로는 CSS IN CSS , CSS MODULE, CSS IN JS 등 다양한 방식이 있습니다. 프로젝트의 성격에 따라 구현하는 방식은 다르겠지만, 오늘은 Styled Components ( CSS IN JS )에 대해서 알아보겠습니다.

     

    우선 Styled Components 를 사용하기 위해서는 가장먼저 스타일 컴포넌트 모듈부터 설치해야 됩니다.

     

    0. Code Snippet 설치

    styled-components snippet

    필수는 아니지만 스타일 컴포넌트가 문자열 처럼 그냥 쭉쭉 나오면 매우 불쾌지수가 올라갑니다. 익스텐션 제가 쓰는 걸 알려드리자면 vscode-styled-components 입니다. 해당 스니펫이 아니더라도 꼭 깔고 작업하시는걸 추천..또 추천드립니다.

     

    1. styled-components 설치

    //npm
    npm i styled-components
    //yarn
    yarn add styled-components

    설치가 끝났다면 테마 컬러와 같은 공통적으로 사용할 theme파일을 생성해 줍니다.

     

    2. 테마 셋팅

     

    파일명 : theme.js

    const theme = {
      palette : {
        red : "#ED1C24",
        gray : "#495057",
        white : "#fff",
      }
    };
    export default theme;

    이렇게 팔레트 처럼 세팅해서 사용할 값들을 테마 안에 정의해 줍시다.

     

    3. 전역 스타일 셋팅

    전역 스타일 셋팅에는 크게 두가지 방법이 있을 것 같습니다. 그냥 import로 최상단(index.js)에 추가하는 방법이 있고 그 외에는 스타일 컴포넌트 내의 GlobalStyle을 이용하는 방법이 있습니다. 그럼 import는 그냥 하면되니 GlobalStyle을 이용하는 방법을 보겠습니다.

     

    파일명 : GlobalStyle.js

    import { createGlobalStyle} from 'styled-components';
    
    const GlobalStyle = createGlobalStyle`
      body {
        margin:0;
        padding:0;
      }
    `;
    export default GlobalStyle;

     

    4. 최상단 컴포넌트에 셋팅

    저같은 경우는 리액트 개발시에 index.js가 최상단의 Root.js를 바라보고 있게 되어 있습니다. 그 후 RootJS내부에 BrowseRouter가 있고 그 안에 App.js컴포넌트가 있는 구조로 되어 있습니다. 그럼 제 코드를 한번 보겠습니다. 실질적인 App.js를 보면 아래와 같습니다. ThemeProvider가 routes를 감싸고 있는 구조로 되어있습니다. 이렇게 해놓으면 하위에서 사용되는 모든 컴포넌트에 스타일 컴포넌트를 적용할 수 있습니다.

     

    파일명 :  App.js

    import React,{ Suspense } from "react";
    import { Routes, Route } from "react-router-dom";
    import { routes } from "src/routes";
    
    
    import { ThemeProvider } from "styled-components";
    import theme from "src/styles/theme";
    import GlobalStyle from "src/styles/GlobalStyle";
    
    const App = () => {
      return (
        <>
          <globalStyle/>
          <ThemeProvider theme={theme}>
            <Routes>
              {routes.map((route, i) => {
                return (
                  <Route
                    key={i}
                    path={route.path}
                    element={
                      <Suspense fallback={<></>}>
                        <route.component />
                      </Suspense>
                    }
                  />
                );
              })}
            </Routes>
          </ThemeProvider>
        </>
      );
    };
    export default App;

     

    이까지 따라오셨으면 기본적인 사용을 위한 셋팅은 모두 끝났습니다. 그럼 실제로 컴포넌트에서 사용하는 모습을 보여드리도록 하겠습니다.

     

    5. 간단 예시 ( 인풋 태그 )

    간단 예시로는 우리가 가장 많이 사용하는 컴포넌트 중에 하나인 Input에 styledComponents를 적용 해보도록 하겠습니다.

     

    파일명 : Input.js

    import styled, { css } from 'styled-components'
    
    const size = {
      large: {
        height: "3rem",
        fontSize: "1.25rem",
      },
      medium: {
        height: "2.25rem",
        fontSize: "1rem",
      },
      small: {
        height: "1.75rem",
        fontSize: "0.875rem",
      }
    }
    
    const sizeStyles = css`
    	${(props) => css`
          height: ${sizes[props.size].height};
          font-size: ${sizes[props.size].fontSize};
        `}
    `;
    
    const StyledInput = styled.input`
      padding-left:1rem;
      border:1px solid black;
      border-radius:5px;
      ${sizeStyles}
    `;
    
    const Input = ({size, ...rest}) => {
      return <StyledInput size={size} {...rest} />;
    };
    Input.defaultProps = {
      size : "medium",
    };
    export default Input;

    가장 먼저, 우리는 styled.<태그명>을 통해서 StyledComponents를 만들 수 있습니다. 위의 예시에서는 input을 만들었고 그 내부에 css로 스타일링 해줍니다. 그 다음 우리는 사이즈 조절이 되는 Input을 만들 예정이기 때문에 size를 컴포넌트 내에 넘깁니다. 

    그 후, 넘겨진 size값은 props를 통해서 css 내부에서 받아 쓸 수 있습니다. 위와 같이 css를 따로 분리하셔도 되고, 아니면 styled.<태그명> 내부에서 ${(props) => return css` `}를 통해서 바로 사용할 수도 있습니다.

     

    부록 : NEXTJS + TypeScript + StyledComponents 에서 적용방법

     

    NEXTJS에선 프리렌더 과정이 있기 때문에 정상동작 하지 않을 수 있습니다. 그렇기 때문에 이를 정상적으로 동작하기 위해서는 한가지 작업이 필요합니다. 1-2-3 번의 동작까지 동일 합니다. 제가 하던 프로젝트가 타입스크립트라 타입스크리

     

    4. 최상단 컴포넌트 _app.ts 셋팅

     

    파일명 : _app.ts

    import type { AppProps } from 'next/app'
    
    import GlobalStyle from 'src/styles/GlobalStyle';
    import theme from 'src/styles/theme';
    import { ThemeProvider } from 'styled-components';
    
    const MyApp = ({ Component, pageProps }: AppProps) => {
      return (
        <>
          <GlobalStyle />
          <ThemeProvider theme={theme}>
            <Component {...pageProps} />
          </ThemeProvider>
        </> 
      );
    }
    export default MyApp;

    사실상 최상위 컴포넌트는 크게 다른것이 없을 것입니다. 하지만 이 후 _document.ts를 셋팅해주는 것이 조금 다릅니다.

     

    5. _document.ts셋팅

     

    파일명 : _document.ts

    import Document, { Html, Head, Main, NextScript, DocumentContext } from "next/document";
    import { ServerStyleSheet } from "styled-components";
    
    export default class CustomDocument extends Document {
        static async getInitialProps(ctx: DocumentContext) {
            const sheet = new ServerStyleSheet();
            const originalRenderPage = ctx.renderPage;
    
            try {
                ctx.renderPage = () =>
                    originalRenderPage({
                        enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
                    });
    
                const initialProps = await Document.getInitialProps(ctx);
                return {
                    ...initialProps,
                    styles: (
                        <>
                            {initialProps.styles}
                            {sheet.getStyleElement()}
                        </>
                    ),
                };
            } finally {
                sheet.seal();
            }
        }
        render() {
            return (
                <Html>
                    <Head></Head>
                    <body>
                        <Main />
                        <NextScript />
                    </body>
                </Html>
            );
        }
    }

    코드를 보면 컨텍스트를 렌더링 할 때 스타일을 안에 집어넣어서 내린다. 라는 과정입니다. 그대로 복붙해서 넣으시면 됩니다. 이후 마지막 바벨 작업이 남았습니다.

     

    6. .babelrc 셋팅

     

    파일명 : .babelrc

    {
        "presets" : ["next/babel"],
        "plugins": [
            [
                "styled-components",
                {
                    "ssr": true,
                    "displayName": true,
                    "preprocess": false
                }
            ]
        ]
    }

    우리는 프로젝트 폴더의 root에 있는 babelrc를 수정하여야 됩니다. 우선 스타일 컴포넌트 내부에 값들에 대해서 알아 보겠습니다.

     

    ssr : 만들어진 스타일이 server-side에서 동작하게 할 것인지를 체크 하는 것입니다. 이것을 꺼두면 일단 불러오고 그 후에 클라이언트에서 스타일을 맥여서 약간 흔들 거리는 느낌을 받을 수 있습니다.

    displayName : 디버그 하기 쉬운 클래스 네임을 사용할래? 물어보는 것입니다.

    preprocess : 전처리 인데 expriment단계니깐 꺼두기로 합시다.

     

    이렇게 NextJS에서의 스타일 컴포넌트 적용까지 좀 알아봤습니다. 저는 스타일 컴포넌트를 회사 사이드 프로젝트에서 사용하고 있는데 재직중인 회사가 그룹 계열사 SI회사다 보니 외주퍼블리셔와의 협업이 쉽지 않아 실제 그룹사 프로젝트에서 사용못하고 있는게 매우 아쉽네요. 다들 회사일에 갠플에 개인공부에 끊임없이 변하는 프론트엔드 때문에 피곤들 하실텐데 힘냅시다!

    반응형

    댓글

Designed by Tistory.