[NextJs] Next.js14에 styled components 적용하기
FrontEnd/React

[NextJs] Next.js14에 styled components 적용하기

728x90

 

Next.js 에 styled components를 적용하는 것 자체는 그렇게 어렵지 않았지만 어느정도 알고 있어야할 사전 지식이 있다.

 

 

아래 문서는 Next.js에서 제공하는 공식문서 중 css-in-js를 설정하는 방법들에 대해 다룬다.

https://nextjs.org/docs/app/building-your-application/styling/css-in-js#styled-components

 

Styling: CSS-in-JS | Next.js

Use CSS-in-JS libraries with Next.js

nextjs.org

 

 

문서 처음부터 아래와 같이 경고를 해주고 있다.

 

 

요약하자면, NextJS 13버전 이후로 react18의 서버컴포넌트와 같은 서버사이드렌더링 기법들이 많이 추가되었는데 그중에서 css-in-js는 서버 환경에서 동작하지 않는다는 말이다.

 

 

그렇다고 css-in-js를 사용하지 못하는 것은 아니다. 서버 컴포넌트에서 사용하지 못하는 것일 뿐 스타일을 사용하는 컴포넌트를 클라이언트 컴포넌트로 사용하면 사용할 수 있다.

 

다만, 이 방식으로 모든 컴포넌트를 클라이언트 컴포넌트로 만들어버리는 것은 서버사이드 렌더링의 장점들을 잃어버리는 것이므로 현재는 스타일 로직과 api등의 정보를 받아오는 데이터 로직을 분리하는 방식으로 해결할 수 있다.

 

( 현재도 css-in-js 를 ssr환경에서 사용할 수 있게 하는 노력은 현재진행형인듯 하다.)

 

 

각설하고, 간단하게 프로젝트를 만들고 next.js에 styled components를 적용시켜 보자.

 

npx create-next-app --typescript

 

 

위 명령어로 간단하게 next.js 프로젝트를 하나 만들어주자.

 

그리고 app 폴더 내에 registry.tsx라는 파일을 하나 만들고 와래와 같은 코드를 작성해준다.

// app/registry.tsx
"use client";

import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";

export default function StyledComponentsRegistry({
  children,
}: {
  children: React.ReactNode;
}) {
  // Only create stylesheet once with lazy initial state
  // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());

  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    return <>{styles}</>;
  });

  if (typeof window !== "undefined") return <>{children}</>;

  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      {children}
    </StyleSheetManager>
  );
}

 

 

 

이후 RootLayout 폴더에 아래와 같이 StyledComponentsRegistry 컴포넌트를 감싸주면 Next.js에서 styledComponents를 사용할 준비가 완료된다. 

// app/layout.tsx
import StyledComponentsRegistry from "./registry";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const componentType = typeof window === "undefined" ? "server" : "client";

  console.log("layout", componentType);
  return (
    <html>
      <body>
        <StyledComponentsRegistry>{children}</StyledComponentsRegistry>
      </body>
    </html>
  );
}

 

 

 

이제 아래와 같이 실제로 styled-components를 사용하면 잘 동작되는것을 알 수 있다.

// app/page.tsx

"use client";
import Image from "next/image";
import styles from "./page.module.css";
import styled from "styled-components";

export default function Home() {
  const componentType = typeof window === "undefined" ? "server" : "client";

  console.log("page", componentType);
  return <Wrapper>asdfasdf</Wrapper>;
}

const Wrapper = styled.div`
  color: blue;
`;

 

 

글의 초반부에 말했던 것처럼 현재 styled-componets는 서버에서 지원이 안되기 때문에 꼭!! "use clinet"를 붙여서 클라이언트 컴포넌트임을 명시해야 한다.

 

 

 

 

서버사이드 렌더링의 이점?

const componentType = typeof window === "undefined" ? "server" : "client";

  console.log("page", componentType);

위 코드로 현재 코드가 작성되는 컴포넌트의 타입을 정할 수 있다.

 

 

"use client"로 작성한 page.tsx의 경우 아래와 같이 콘솔창에 찍힌다.

 

 

 

 

 

그리고 layout component는 서버에서만 콘솔이 찍히는것을 확인할 수 있다.

 

 

이런점을 이용해서 현재 서버사이드의 이점과 css-in-js를 사용하려면 로직을 잘 분리하는 것이 최선인 듯 하다..

728x90