React Router

React RouterのプロジェクトにYamada UIをインストールして使用するためのガイド。

インストール

  • 1

    アプリケーションを作成する

    React Routerのアプリケーションを作成します。

    pnpm create react-router my-app
    
  • 2

    セットアップする

    コマンドを実行すると、プロジェクトに必要なファイルやフォルダが作成されます。

    pnpm dlx @yamada-ui/cli init
    
  • 3

    パッケージをインストールする

    アプリケーションに@workspaces/uiをインストールします。

    pnpm add "@workspaces/ui@workspace:*"
    
  • 4

    プロバイダーを追加する

    インストール後、アプリケーションのルートにUIProviderを追加します。 ハイドレーションエラーを抑制するために、htmlbodysuppressHydrationWarningtrueに設定します。

    root.tsx

    import { Meta, Outlet, Scripts, ScrollRestoration } from "react-router"
    import { UIProvider } from "@workspaces/ui"
    
    export function Layout({ children }: { children: React.ReactNode }) {
      return (
        <html lang="en" suppressHydrationWarning>
          <head>
            <meta charSet="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <Meta />
          </head>
          <body suppressHydrationWarning>
            <UIProvider>{children}</UIProvider>
            <ScrollRestoration />
            <Scripts />
          </body>
        </html>
      )
    }
    
    export default function App() {
      return <Outlet />
    }
    
  • 5

    コンポーネントを使用する

    UIProviderを追加したら、アプリケーション内でコンポーネントを使用します。

    home.tsx

    import { Button } from "@workspaces/ui"
    
    export default function Home() {
      return <Button>Click me!</Button>
    }
    

    これで、Yamada UIのセットアップは完了です!

スクリプト

ColorModeScript

カラーモードを使用する場合は、正常に動作させるためにbodyColorModeScriptを追加する必要があります。

理由は、カラーモードがlocalStoragecookiesを用いて実装されており、ページの読み込み時に同期を正しく機能させるためです。

root.tsx

import {
  data,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  useRouteLoaderData,
} from "react-router"
import { ColorModeScript, UIProvider } from "@workspaces/ui"
import type { Route } from "./+types/root"

export async function loader({ request }: Route.LoaderArgs) {
  const cookie = request.headers.get("cookie") ?? ""
  return data({ cookie })
}

export function Layout({ children }: { children: React.ReactNode }) {
  const { cookie } = useRouteLoaderData("root")

  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
      </head>
      <body suppressHydrationWarning>
        <ColorModeScript type="cookie" />

        <UIProvider cookie={cookie}>{children}</UIProvider>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  )
}

export default function App() {
  return <Outlet />
}

もし、コンフィグdefaultColorModeを変更した場合は、ColorModeScriptdefaultValueを設定します。

root.tsx

import {
  data,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  useRouteLoaderData,
} from "react-router"
import { ColorModeScript, UIProvider } from "@workspaces/ui"
import type { Route } from "./+types/root"
import { config } from "@workspace/theme"

export async function loader({ request }: Route.LoaderArgs) {
  const cookie = request.headers.get("cookie") ?? ""
  return data({ cookie })
}

export function Layout({ children }: { children: React.ReactNode }) {
  const { cookie } = useRouteLoaderData("root")

  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
      </head>
      <body suppressHydrationWarning>
        <ColorModeScript type="cookie" defaultValue={config.defaultColorMode} />

        <UIProvider config={config} cookie={cookie}>
          {children}
        </UIProvider>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  )
}

export default function App() {
  return <Outlet />
}

ThemeSchemeScript

テーマスキームによる画面のフラッシュを抑制したい場合は、body内にThemeSchemeScriptを追加します。

テーマスキームはlocalStoragecookiesを用いて実装されており、ThemeSchemeScriptを追加することでページの読み込み時に同期を正しく機能させることができます。

root.tsx

import {
  data,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  useRouteLoaderData,
} from "react-router"
import { ThemeSchemeScript, UIProvider } from "@workspaces/ui"
import type { Route } from "./+types/root"

export async function loader({ request }: Route.LoaderArgs) {
  const cookie = request.headers.get("cookie") ?? ""
  return data({ cookie })
}

export function Layout({ children }: { children: React.ReactNode }) {
  const { cookie } = useRouteLoaderData("root")

  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
      </head>
      <body suppressHydrationWarning>
        <ThemeSchemeScript type="cookie" />

        <UIProvider cookie={cookie}>{children}</UIProvider>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  )
}

export default function App() {
  return <Outlet />
}

もし、コンフィグdefaultThemeSchemeを変更した場合は、ThemeSchemeScriptdefaultValueを設定します。

root.tsx

import {
  data,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  useRouteLoaderData,
} from "react-router"
import { ThemeSchemeScript, UIProvider } from "@workspaces/ui"
import type { Route } from "./+types/root"
import { config } from "@workspace/theme"

export async function loader({ request }: Route.LoaderArgs) {
  const cookie = request.headers.get("cookie") ?? ""
  return data({ cookie })
}

export function Layout({ children }: { children: React.ReactNode }) {
  const { cookie } = useRouteLoaderData("root")

  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
      </head>
      <body suppressHydrationWarning>
        <ThemeSchemeScript
          type="cookie"
          defaultValue={config.defaultThemeScheme}
        />

        <UIProvider config={config} cookie={cookie}>
          {children}
        </UIProvider>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  )
}

export default function App() {
  return <Outlet />
}