コンテンツにスキップ

CSS-in-JS ライブラリの使用方法

注意: Server Components や Streaming のような新しい React の機能と CSS-in-JS を併用する場合、ライブラリの作者は、concurrent rendering の最新バージョンをサポートする必要があります。

次のライブラリは、app ディレクトリの Client Components でサポートされています(アルファベット順)。

現在、サポートに取り組んでいるのは以下の通りです。

知っておくと良いこと:さまざまな CSS-in-JS ライブラリをテストしており、React 18 の機能や app ディレクトリをサポートするライブラリの追加例を掲載する予定です。

app での CSS-in-JS の設定

CSS-in-JS の設定は、3 つのステップからなるオプトインプロセスです。

  1. レンダリングされたすべての CSS ルールを収集するためのスタイルレジストリ
  2. 使用する可能性のあるコンテンツの前にルールを挿入するための新しい useServerInsertedHTML フック。
  3. 初期サーバーサイドレンダリング中にスタイルレジストリでアプリをラップする Client Component。

styled-jsx

Client Components で 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
}) {
  // Only create stylesheet once with lazy initial state
  // x-ref: https://react.dokyumento.jp/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>
  )
}

例はこちらで表示.

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
}) {
  // Only create stylesheet once with lazy initial state
  // x-ref: https://react.dokyumento.jp/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>
  )
}

例はこちらで表示.

知っておくと良いこと:

  • サーバーレンダリング中、スタイルはグローバルレジストリに抽出され、HTML の <head> にフラッシュされます。これにより、スタイルルールがそれらを使用する可能性のあるコンテンツの前に配置されることが保証されます。将来的には、React の今後の機能を使用して、スタイルの挿入場所を決定する可能性があります。
  • ストリーミング中、各チャンクからのスタイルが収集され、既存のスタイルに追加されます。クライアントサイドのハイドレーションが完了すると、styled-components が通常どおり引き継ぎ、それ以降の動的なスタイルを挿入します。
  • スタイルレジストリのツリーの最上位に Client Component を使用したのは、CSS ルールをこのように抽出する方が効率的だからです。これにより、後続のサーバーレンダリングでスタイルが再生成されることが回避され、Server Component のペイロードで送信されることがなくなります。
  • styled-components のコンパイルの個々のプロパティを設定する必要がある高度なユースケースについては、Next.js styled-components API リファレンスを参照してください。