実践
Next.jsでPaginationによるページ送り、保存済み下書きのプレビュー、nextRevalidateプラグインによるキャッシュ再検証を設定する手順。
導入で作った一覧・詳細ページに、運用で必要になる3つを足します。
ページ送り
Listの直下にPaginationを置くだけで、limitの件数ごとに切り替わります。既定のmode="local"はURLを変えずに一覧だけを差し替えます。
<List api={client.blog} limit={6} orders="-publishedAt" href="/blog/{id}"> <article><h2><ListItem id="title" /></h2></article> <Pagination /> <Error template /> <Null>公開されている記事はありません。</Null></List>URLに残したいときはmode="url"にして、ページのsearchParamsをListにも渡します。ブラウザの戻る・進む・再読み込みに対応し、?page=2を直接開いてもサーバー側で2ページ目を描画します。
import { client } from "@/lib/client";import { List, ListItem, Pagination, Error, Null } from "@genko-me/react/next";
type Props = { searchParams: Promise<Record<string, string | string[] | undefined>>;};
export default function NewsPage({ searchParams }: Props) { return ( <main> <h1>お知らせ</h1> <List api={client.blog} limit={10} orders="-publishedAt" href="/blog/{id}" searchParams={searchParams}> <article><h3><ListItem id="title" /></h3></article> <Pagination mode="url" param="page" previousLabel="前へ" nextLabel="次へ" /> <Error template /> <Null>お知らせはありません。</Null> </List> </main> );}Paginationが描画するのは<nav aria-label="ページ送り">と、前後のボタン・現在位置(1 / 3)だけです。標準の装飾は付かないので、classNameでサイトのデザインを当ててください。先頭・末尾のページでは対応するボタンがdisabledになり、1ページに収まる件数のときはPagination自体を描画しません。
1つのページでURL連動の一覧を2つ使う場合は、paramを別々の名前にします。
制約。 PaginationはSDK内のServer Actionで次のページを取得します。静的エクスポート(output: "export")とEdgeランタイムでは動作しません。カスタムfetchやwrapRequestを設定したクライアントも対象外です。署名の有効期限は1時間で、期限切れやAPIキーの交換後はページを再読み込みしてください。
保存済み下書きのプレビュー
詳細ページのsearchParamsをViewに渡していれば、追加のRoute Handlerなしでプレビューになります。導入のコードのままで動きます。
管理画面のAPI設定(/w/your-workspace/apis/blog/settings)で、プレビューURLテンプレートを設定します。
https://your-site.example/blog/{id}?draftKey={key}{id}と{key}は管理画面が置き換えます。ローカルで確認するときはホストをhttp://localhost:3000に変えてください。
記事を保存して「プレビュー」を押すと、同じ詳細ページに下書きが表示されます。このときViewは次の処理を行います。
- 下書きをキャッシュせず取得する(公開表示に
cacheを指定していても影響しません)。 - ページに
noindex, nofollowとno-referrerのmetaを出す。 - プレビュー中であることの通知と、終了ボタンを表示する。
終了ボタンはURLからdraftKeyを外して公開表示に戻ります。キーが正しくない場合は、公開版へ切り替えずにNull(notFoundを指定していれば404画面)になります。
通知の位置と装飾はpreviewNoticeで調整します。
<View api={client.blog} id={id} searchParams={searchParams} previewNotice={{ position: "bottom", className: "preview-bar" }}>previewNotice={false}で非表示、previewNotice={{ unstyled: true }}で標準の装飾だけを外せます。通知は親のunstyledの影響を受けません。
プレビュー用のRoute Handlerを別に用意し、Draft Modeを有効にしてから詳細ページへ飛ばす構成にもできます。@genko-me/sdk/nextのnextPreviewが、idとdraftKeyを読んで307でリダイレクトするハンドラーを提供します。詳しくはプラグインとNext.js連携を参照してください。
Webhookで再生成・再検証する
記事を更新したときにキャッシュを作り直すには、genko.me側のWebhookとnextRevalidateプラグインを使います。
まずlib/client.tsのクライアントにプラグインを足します。
import "server-only";import { createGenko } from "@genko-me/sdk";import { nextRevalidate } from "@genko-me/sdk/next";import { apis } from "./schema";
export const genko = createGenko({ workspace: "your-workspace", apiKey: process.env.GENKO_API_KEY!, apis, plugins: [ nextRevalidate({ secret: process.env.GENKO_WEBHOOK_SECRET!, revalidate: (event) => { if (event.api !== "blog" || event.workspace !== "your-workspace") return []; if (event.event === "webhook.test") return ["/blog"]; return event.entry ? ["/blog", `/blog/${event.entry.id}`] : ["/blog"]; }, }), ],});export const client = genko.apis;プラグインのPOSTをRoute Handlerとして公開します。
import { genko } from "@/lib/client";
export const POST = genko.revalidate.POST;管理画面のAPI設定から「Webhookを追加」で、通知先にhttps://your-site.example/api/revalidate、シークレットにGENKO_WEBHOOK_SECRETと同じ値を設定します。署名が一致するとrevalidateが返したパスごとにrevalidatePath()を呼び、{"revalidated":["/blog","/blog/1"]}のようなJSONを返します。一致しない場合は401です。シークレットが空だとクライアントの初期化時にエラーになります。
キャッシュしていないページには効果がありません。 List・Viewは既定で毎回取得します。再検証が意味を持つのはcache={60}のように秒数を指定した一覧・詳細です。
<List api={client.blog} limit={6} orders="-publishedAt" cache={60}>削除・公開終了のイベントでは、一覧だけでなく個別ページのパスも再検証してください。entry.statusがdraftに戻ったときも同じです。手動で「公開」にして保存した場合のイベントはentry.publishedではなくentry.created / entry.updatedになります。イベントの一覧と配送の制限はWebhookにまとめています。
ホスティング先の再ビルドで運用する場合は、受信URLをデプロイフックにします。その場合このプラグインは不要です。
次に読む
最終更新: 2026年9月17日