機能このページを編集.md

HTTP コンテクスト

@lazarv/react-server を使用すると、サーバーサイドレンダリングのコンテクストに関連するすべてにアクセスできます。このガイドでは、HTTPコンテクストにアクセスする方法について説明します。

これから紹介するものは、HTTPコンテクストにアクセスして操作するためのフックまたは関数です。

これらの関数はすべて、ミドルウェアやファイルシステムベースのルーターを使用したルートハンドラーでも利用可能です。これらはランタイム固有であり、Reactとは関係ありません。

useHttpContext() を使用すると、完全なHTTPコンテクストにアクセスできます。

import { useHttpContext } from "@lazarv/react-server"; export default function MyComponent() { const context = useHttpContext(); return ( <div> <p>Method: {context.request.method}</p> <p>URL: {context.request.url.toString()}</p> <p>Request Headers: {JSON.stringify(context.request.headers)}</p> <p>Request Cookies: {JSON.stringify(context.request.cookie)}</p> </div> ); };

useRequest() を使用すると、完全なHTTPリクエストにアクセスできます。

import { useRequest } from "@lazarv/react-server"; export default function MyComponent() { const request = useRequest(); return ( <div> <p>Method: {request.method}</p> <p>URL: {request.url.toString()}</p> <p>Headers: {JSON.stringify(request.headers)}</p> <p>Cookies: {JSON.stringify(request.cookie)}</p> </div> ); };

useResponse() を使用すると、完全なHTTPレスポンスにアクセスできます。これは、レスポンスがクライアントに送信された後、サスペンドされ、後でクライアントにストリーミングされたReactコンポーネント内でのみ利用可能です。

import { useResponse } from "@lazarv/react-server"; export default async function MyComponent() { const response = await useResponse(); return ( <div> <p>Headers: {JSON.stringify(response.headers)}</p> <p>Cookies: {JSON.stringify(response.cookie)}</p> </div> ); };

useUrl() を使用すると、現在のリクエストのURLにアクセスできます。

import { useUrl } from "@lazarv/react-server"; export default function MyComponent() { const url = useUrl(); return <p>URL: {url.href}</p>; };

usePathname() を使用すると、現在のリクエストのパス名にアクセスできます。

import { usePathname } from "@lazarv/react-server"; export default function MyComponent() { const pathname = usePathname(); return <p>Pathname: {pathname}</p>; };

useSearchParams() を使用すると、現在のリクエストの検索パラメータにアクセスできます。これは、検索パラメータのキーと値のペアを持つオブジェクトです。同じキーに複数の値がある場合、その値は配列になります。

import { useSearchParams } from "@lazarv/react-server"; export default function MyComponent() { const searchParams = useSearchParams(); return ( <p>Search params: {JSON.stringify(searchParams)}</p> ); };

headers() を使用すると、現在のリクエストのヘッダーにアクセスできます。

import { headers } from "@lazarv/react-server"; export default function MyComponent() { const requestHeaders = headers(); return <p>Headers: {JSON.stringify(requestHeaders)}</p>; };

キーと値のペアのオブジェクトを渡すことで、現在のレスポンスのヘッダーを変更することもできます。

import { headers } from "@lazarv/react-server"; export default function MyComponent() { headers({ "X-My-Header": "My value", }); return <p>Headers: {JSON.stringify(headers())}</p>; };

または、Headers オブジェクトを渡すことでも変更できます。

import { headers } from "@lazarv/react-server"; export default function MyComponent() { headers(new Headers({ "X-My-Header": "My value", })); return <p>Headers: {JSON.stringify(headers())}</p>; };

または、キーと値のペアの配列を渡すことでも変更できます。

import { headers } from "@lazarv/react-server"; export default function MyComponent() { headers([ ["X-My-Header", "My value"], ]); return <p>Headers: {JSON.stringify(headers())}</p>; };

headers() 関数を使用してヘッダーを変更すると、現在のレスポンスのヘッダーが上書きされます。レスポンスヘッダーを直接変更したい場合は、ヘッダーを設定、追加、削除するための3つの補助関数を使用できます。これらの関数は setHeader()appendHeader()、および deleteHeader() です。

import { setHeader, appendHeader, deleteHeader } from "@lazarv/react-server"; export default function MyComponent() { setHeader("X-My-Header", "My first value"); appendHeader("X-My-Header", "My second value"); deleteHeader("X-My-Header"); return <p>Check the response headers!</p>; }

注意: HTTPヘッダーは大文字と小文字を区別しないことに注意してください!

cookie() を使用すると、現在のリクエストのクッキーにアクセスできます。

import { cookie } from "@lazarv/react-server"; export default function MyComponent() { const requestCookies = cookie(); return <p>Cookies: {JSON.stringify(requestCookies)}</p>; };

また、現在のレスポンスのコンテクストでクッキーを設定または削除することもできます。

import { setCookie, deleteCookie } from "@lazarv/react-server"; export default function MyComponent() { setCookie("my-cookie", "my-value"); deleteCookie("other-cookie"); return <p>Cookies: {JSON.stringify(cookie())}</p>; };

status() を使用すると、現在のレスポンスのステータスコードとテキストを設定できます。

import { status } from "@lazarv/react-server"; export default function MyComponent() { status(404, "Not found"); return <p>Not Found</p>; };

useFormData() を使用すると、現在のリクエストのフォームデータにアクセスできます。

import { useFormData } from "@lazarv/react-server"; export default function MyComponent() { const formData = useFormData(); return ( <p>Form data: {JSON.stringify(Object.fromEntries(formData.entries()))}</p> ); };

redirect() を使用すると、現在のリクエストを別のURLにリダイレクトできます。

警告: redirect() 関数はエラーをスローし、ランタイムがそれをキャッチしてリダイレクトを実行します。try/catch ブロック内で redirect() を使用する場合、リダイレクトエラーであれば再スローすることを確認してください。

import { redirect } from "@lazarv/react-server"; export default function MyComponent() { redirect("https://example.com"); };

redirect() 関数は、クライアントでのリダイレクトの動作を制御するオプションの第3引数 kind を受け付けます。利用可能な種類は以下の通りです:

種類説明
"navigate"(デフォルト) replaceState を使用したRSCナビゲーションを実行します。ブラウザのURLは変更されますが、履歴エントリは追加されません。
"push"pushState を使用したRSCナビゲーションを実行します。ブラウザのURLが変更され、新しい履歴エントリが追加されるため、ユーザーは戻るボタンで戻ることができます。
"location"location.href を使用した完全なブラウザナビゲーションを強制します。外部URLへのリダイレクトやページの完全なリロードが必要な場合に便利です。
"error"ナビゲーションの代わりにクライアントでリダイレクトエラーをスローします。サーバーアクション呼び出しで try/catch によるカスタム処理が可能になります。
import { redirect } from "@lazarv/react-server"; // pushStateを使用したRSCナビゲーション(履歴エントリを追加) redirect("/dashboard", 302, "push"); // 完全なブラウザナビゲーション redirect("/oauth/authorize", 302, "location"); // カスタム処理のためにクライアントでスロー redirect("/login", 302, "error");

サーバーアクションで "error" 種類を使用する場合、クライアントでリダイレクトエラーをキャッチして処理できます:

"use client"; import { myServerAction } from "./actions"; export function MyComponent() { const handleClick = async () => { try { await myServerAction(); } catch (e) { if (e?.digest?.startsWith("Location=")) { const url = e.digest.split("Location=")[1]?.split(";")[0]; console.log(`リダイレクト先: ${url}`); } } }; return <button onClick={handleClick}>送信</button>; }

rewrite() を使用すると、現在のリクエストを別のURLにリライトできます。これは、ミドルウェア関数内で現在のリクエストのURLパス名を変更するのに便利です。

import { rewrite, useUrl } from "@lazarv/react-server"; export function init$() { return async () => { const { pathname } = useUrl(); if (pathname === "/old-pathname") { rewrite("/new-pathname"); } }; } export default function MyComponent() { const { pathname } = useUrl(); return <p>Current pathname: {pathname}</p>; }

useOutlet() を使用すると、現在のリクエストのアウトレットにアクセスできます。これは、現在のリクエストがレンダリングされているアウトレットの名前を取得するのに便利です。

import { useOutlet } from "@lazarv/react-server"; export default function MyComponent() { const outlet = useOutlet(); return <p>Outlet: {outlet}</p>; }

useRender() を使用すると、現在のリクエストのレンダーロックにアクセスできます。これは、非同期関数が実行されている間、またはロックが解除されるまで、React Server Componentのレンダリングをロックしたい場合に便利です。なぜならReact Server Componentはデフォルトでストリーミングを使用してレンダリングされるからです。特にHTTPヘッダーやクッキーを非同期のReact Server Componentで処理する場合に役立ちます。レンダリングをロックしないと、非同期関数が終了する前にヘッダーやクッキーがクライアントに送信されてしまいます。レンダリングプロセスでロックが検出されると、レンダリングはロックが解除されるまで待機し、ヘッダーやクッキーの送信を開始してからReact Server Componentのストリーミングを開始します。

import { headers, useRender } from "@lazarv/react-server"; export default function MyComponent() { const { lock } = useRender(); await lock(async () => { // Do something async await new Promise((resolve) => setTimeout(resolve, 1000)); headers({ "x-lock": "works", }); }); return <p>Render lock</p>; }

lock() 関数を使用して、後でロックを解除するための unlock() 関数を取得することもできます。

import { headers, useRender } from "@lazarv/react-server"; export default function MyComponent() { const { lock } = useRender(); const unlock = lock(); // Do something async await new Promise((resolve) => setTimeout(resolve, 1000)); headers({ "x-lock": "works", }); unlock(); return <p>Render lock</p>; }