💬

Remixの共通レイアウトにHeaderコンポーネントを入れるには?

2024/04/14に公開

Remixのルートにはapp\root.tsx共通レイアウトをいれますが、Appと場合によってはLayoutも定義されています。

ではHeaderコンポーネントを定義したらどこに配置すればいいでしょうか?

  1. Headerコンポーネントを作る
  2. rootで呼び出す
  3. AppにHeaderを入れる

1. Headerコンポーネントを作る

appディレクトリにcomponentsディレクトリを作成します。そこにHeader.tsxを作ります。

ログイン機能をつける前提で、ログインしていたら右上にアイコンがでます。

app\components\Header.tsx
app\components\Header.tsx

import {
  UserButton,
  useAuth,
  SignInButton
} from "@clerk/remix";
import { Link } from "@remix-run/react";

export default function Index() {
  const { isLoaded, userId } = useAuth();

  if (!isLoaded) {
    return <div>Loading...</div>; // Handle loading state
  }

  return (
    <div>
      <header className="flex h-16 w-full items-center border-b px-4 md:px-6">
        <Link className="inset-y-0 flex items-center gap-2 font-semibold" to="#">
          Acme Inc
        </Link>
        <nav className="flex flex-1 justify-center font-medium">
          <Link className="mx-2" to="#">
            Home
          </Link>
          <Link className="mx-2" to="#">
            About
          </Link>
          <Link className="mx-2" to="#">
            Contact
          </Link>
        </nav>
        <div>
          {userId ? (
            <UserButton /> // Renders user button when logged in
          ) : (
            <SignInButton>Sign in with Clerk</SignInButton> // Button to initiate sign-in
          )}
        </div>
      </header>
    </div>
  );
}

2. rootでHeaderコンポーネントを呼び出す

app\root.tsx
app\root.tsx
+import Header from "~/components/Header";

3. AppにHeaderを入れる

なぜ `App` に `Header` を配置するのか?

Header コンポーネントを App コンポーネントに配置する主な理由は以下の通りです:

  1. 認証コンテキストの維持:

    • Headerにはログイン機能が組み込まれており(UserButtonSignInButtonを使用)、これはClerkAppから提供される認証コンテキストに依存します。
    • ClerkAppによって提供される認証状態を、Appとその子コンポーネントが利用できます。HeaderApp内に配置することで、認証情報へのアクセスが保証され、認証状態に基づくUIの適切な更新が可能になります。
  2. 全ページでの一貫した表示:

    • Appはアプリケーションのすべてのページの基本となるコンポーネントです。Outletを通じて描画されるすべてのページに対してHeaderが表示されるようにします。
    • 各ページへの移動があってもHeaderが常に表示されるため、ユーザーに一貫したナビゲーション体験を提供できます。
  3. パフォーマンスと最適化:

    • App内でHeaderをレンダリングすることにより、ページ遷移時にHeaderのDOMが再生成されることなく、Reactが必要な部分だけを再描画します。これにより、パフォーマンスが向上し、不要なリソースのロードが減少します。
  4. 設計のシンプルさ:

    • HeaderAppの直下に配置することで、デザインとコードがシンプルになり、管理が容易になります。新しい開発者がプロジェクトに参加した場合でも、コードの理解と修正がしやすくなります。

これらの理由から、Appコンポーネント内にHeaderを配置することは、一貫性、パフォーマンス、アクセス性、そして管理の容易さを考慮した最適な選択となります。

app\root.tsx
app\root.tsx
import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration
} from "@remix-run/react";
import type {  LoaderFunction,LinksFunction } from "@remix-run/node";
import { rootAuthLoader } from "@clerk/remix/ssr.server";
import { ClerkApp, ClerkErrorBoundary } from "@clerk/remix"; 


import Header from "~/components/Header";
export const loader: LoaderFunction = (args) => rootAuthLoader(args);
export const ErrorBoundary = ClerkErrorBoundary();

import stylesheet from "~/tailwind.css?url";

export const links: LinksFunction = () => [
  { rel: "stylesheet", href: stylesheet },
];



export function Layout({ children }: { children: React.ReactNode }) {

  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body className="max-w-[1000px] mx-auto">
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}


function App() {
  return (
    <>
+      <Header /> 
      <Outlet />
    </>
  );
}

export default ClerkApp(App);

Discussion