문서
App Router 사용하기
CSS-in-JS

CSS-in-JS

경고: 런타임 JavaScript가 필요한 CSS-in-JS 라이브러리는 현재 서버 컴포넌트에서 지원되지 않습니다. 서버 컴포넌트 및 스트리밍과 같은 최신 React 기능과 함께 CSS-in-JS를 사용하려면 라이브러리 작성자가 동시 렌더링을 포함한 최신 버전의 React를 지원해야 합니다.

우리는 React 서버 컴포넌트 및 스트리밍 아키텍처를 지원하는 CSS 및 JavaScript 자산을 처리하기 위한 상위 API에 대해 React 팀과 협력하고 있습니다.

다음 라이브러리는 app 디렉토리의 클라이언트 컴포넌트에서 지원됩니다(알파벳 순):

다음은 현재 지원을 위해 작업 중입니다:

알아두면 좋은 점: 우리는 다양한 CSS-in-JS 라이브러리를 테스트하고 있으며, React 18 기능 및/또는 app 디렉토리를 지원하는 라이브러리에 대한 더 많은 예제를 추가할 예정입니다.

서버 컴포넌트에 스타일을 적용하려면 CSS 모듈이나 PostCSS 또는 Tailwind CSS와 같이 CSS 파일을 출력하는 다른 솔루션을 사용하는 것을 권장합니다.

app에서 CSS-in-JS 구성하기

CSS-in-JS를 구성하는 것은 세 단계의 선택적 과정으로, 다음을 포함합니다:

  1. 렌더링에서 모든 CSS 규칙을 수집하는 스타일 레지스트리.
  2. 규칙을 사용할 수 있는 콘텐츠보다 먼저 규칙을 주입하기 위한 새로운 useServerInsertedHTML 훅.
  3. 초기 서버 사이드 렌더링 중에 스타일 레지스트리로 앱을 감싸는 클라이언트 컴포넌트.

styled-jsx

클라이언트 컴포넌트에서 styled-jsx를 사용하려면 v5.1.0을 사용해야 합니다. 먼저 새 레지스트리를 만듭니다:

app/registry.tsx
"use client";
 
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { StyleRegistry, createStyleRegistry } from "styled-jsx";
 
export default function StyledJsxRegistry({
  children,
}: {
  children: React.ReactNode;
}) {
  // 지연 초기 상태로 스타일시트를 한 번만 생성
  // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
  const [jsxStyleRegistry] = useState(() => createStyleRegistry());
 
  useServerInsertedHTML(() => {
    const styles = jsxStyleRegistry.styles();
    jsxStyleRegistry.flush();
    return <>{styles}</>;
  });
 
  return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>;
}
app/registry.js
"use client";
 
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { StyleRegistry, createStyleRegistry } from "styled-jsx";
 
export default function StyledJsxRegistry({ children }) {
  // 지연 초기 상태로 스타일시트를 한 번만 생성
  // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
  const [jsxStyleRegistry] = useState(() => createStyleRegistry());
 
  useServerInsertedHTML(() => {
    const styles = jsxStyleRegistry.styles();
    jsxStyleRegistry.flush();
    return <>{styles}</>;
  });
 
  return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>;
}

그런 다음 루트 레이아웃을 레지스트리로 감쌉니다:

app/layout.tsx
import StyledJsxRegistry from "./registry";
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <StyledJsxRegistry>{children}</StyledJsxRegistry>
      </body>
    </html>
  );
}
app/layout.js
import StyledJsxRegistry from "./registry";
 
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <StyledJsxRegistry>{children}</StyledJsxRegistry>
      </body>
    </html>
  );
}

여기에서 예제를 확인하세요.

Styled Components

다음은 styled-components@6 이상을 구성하는 방법의 예시입니다:

먼저 next.config.js에서 styled-components를 활성화합니다.

next.config.js
module.exports = {
  compiler: {
    styledComponents: true,
  },
};

그런 다음 styled-components API를 사용하여 렌더링 중에 생성된 모든 CSS 스타일 규칙을 수집하는 전역 레지스트리 컴포넌트와 해당 규칙을 반환하는 함수를 만듭니다. 그리고 useServerInsertedHTML 훅을 사용하여 레지스트리에서 수집한 스타일을 루트 레이아웃의 <head> HTML 태그에 주입합니다.

lib/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;
}) {
  // 지연 초기 상태로 스타일시트를 한 번만 생성
  // 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>
  );
}
lib/registry.js
"use client";
 
import React, { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
 
export default function StyledComponentsRegistry({ children }) {
  // 지연 초기 상태로 스타일시트를 한 번만 생성
  // 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>
  );
}

루트 레이아웃의 children을 스타일 레지스트리 컴포넌트로 감쌉니다:

app/layout.tsx
import StyledComponentsRegistry from "./lib/registry";
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <StyledComponentsRegistry>{children}</StyledComponentsRegistry>
      </body>
    </html>
  );
}
app/layout.js
import StyledComponentsRegistry from "./lib/registry";
 
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <StyledComponentsRegistry>{children}</StyledComponentsRegistry>
      </body>
    </html>
  );
}

여기에서 예제를 확인하세요.

알아두면 좋은 점:

  • 서버 렌더링 중에 스타일은 전역 레지스트리로 추출되어 HTML의 <head>에 플러시됩니다. 이는 스타일 규칙이 사용할 수 있는 콘텐츠보다 먼저 배치되도록 보장합니다. 향후에는 스타일을 주입할 위치를 결정하기 위해 곧 나올 React 기능을 사용할 수 있습니다.
  • 스트리밍 중에는 각 청크의 스타일이 수집되어 기존 스타일에 추가됩니다. 클라이언트 측 하이드레이션이 완료된 후에는 styled-components가 평소와 같이 인계받아 추가적인 동적 스타일을 주입합니다.
  • 우리는 스타일 레지스트리를 위해 트리의 최상위 수준에서 특별히 클라이언트 컴포넌트를 사용합니다. 이 방법이 CSS 규칙을 추출하는 데 더 효율적이기 때문입니다. 이는 후속 서버 렌더링에서 스타일을 재생성하는 것을 방지하고, 서버 컴포넌트 페이로드로 전송되는 것을 방지합니다.
  • styled-components 컴파일의 개별 속성을 구성해야 하는 고급 사용 사례의 경우, Next.js styled-components API 참조에서 자세한 내용을 확인할 수 있습니다.