List・Viewで表示する
スキーマに沿った表示、状態表示、ページ送り、下書きプレビューをSDKの部品で組み立てます。
Next.js App Router用の、取得から表示までを担当する部品です。以下は公開版@genko-me/[email protected]のAPIに対応しています。Next.js 16以降、React 19、Node.jsランタイムを対象にしています。
取得・表示・ページ送りはSDKに任せ、ページのURLとレイアウトはアプリ側で用意します。CLIは接続用の2ファイルと設定を生成しますが、ページのひな形は生成しません。最初の一覧・詳細はクイックスタートの例を配置してください。
閲覧数の計測と表示にはPV(ページビュー)のPageView・ViewCountを使います。
導入
npx @genko-me/cli initNext.jsを依存に持つプロジェクトでは、CLIがSDK・React部品を追加し、lib/schema.ts と lib/client.ts を生成します。APIキーはサーバーの GENKO_API_KEY に設定します。Route HandlerやProxyの追加は不要です。
以下の一覧例は、blogにtitleとimageフィールドがある場合です。実際のフィールドIDに置き換えてください。
import { client } from '@/lib/client';import { List, ListItem, Pagination, Error, Null } from '@genko-me/react/next';
export default function Page() { return <List api={client.blog} limit={6} orders="-publishedAt" href="/blog/{id}"> <article> <h2><ListItem id="title" /></h2> <ListItem id="image" fallback={<span>画像なし</span>} /> </article> <Pagination /> <Error template /> <Null>記事はまだありません。</Null> </List>;}List の通常の子要素が1件分のレイアウトです。Pagination・Loading・Error・Null は直下に配置し、繰り返しません。状態部品を省略すると、その状態では何も表示しません。template を指定したときだけ標準メッセージを表示します。
詳細と下書き
import { client } from '@/lib/client';import { View, ViewItem, Error, Null } from '@genko-me/react/next';
type Props = { params: Promise<{ id: string }>; searchParams: Promise<Record<string, string | string[] | undefined>>;};
export default async function Page({ params, searchParams }: Props) { const { id } = await params; return <View api={client.blog} id={id} searchParams={searchParams}> <h1><ViewItem id="title" /></h1> <ViewItem id="body" /> <Error template /> <Null>記事がありません。</Null> </View>;}管理画面のプレビューURLを https://your-site.example/blog/{id}?draftKey={key} に設定します。searchParams を渡すと、保存済み下書きをキャッシュせず取得し、プレビュー表示と終了ボタンを出します。不正なキーで公開版へ切り替えることはありません。previewNotice={false} で表示を隠すか、previewNotice={{position:'bottom',className:'...'}} で調整できます。
オブジェクト形式のAPIでは id を省略します。記事がない場合は Null、notFound を指定するとNext.jsの404画面になります。ストリーミング開始後はNext.jsの仕様上HTTPステータスが200になる場合があります。
サーバーとブラウザの境界
client.tsとList / Viewを使うページはサーバーコンポーネントにします。ページに"use client"を付けたり、APIクライアントをクライアントコンポーネントのpropsへ渡したりしないでください。ページ送りなどブラウザで必要な処理はSDK内部で扱います。
アニメーションなどのクライアント部品で囲む場合は、サーバー側で組み立てたList / Viewをその部品のchildrenとして渡せます。
デザインはサイト側で指定する
List・View・フィールド・ページ送り・状態表示は標準の装飾を付けません。className・styleと、見出しやdivなどのHTMLでサイトのデザインを適用します。本文の見出し・段落間隔・画像サイズもサイト側のCSSで設定してください。複数行テキストの改行を表示する場合はwhite-space: pre-wrapなどを指定します。
templateは状態用の標準メッセージを選ぶ指定で、枠線や余白は追加しません。unstyledは既存コードとの互換性のため受け付けますが、これらの部品の装飾は切り替えません。unstyled={false}でも標準デザインは付きません。
標準メッセージとページ送り・下書きプレビュー帯の文言は、List・Viewに渡したlangに合わせて日本語か英語で出ます。jaか未指定なら日本語、それ以外の言語(en・frなど)は英語です。部品ごとにlangを渡して変えることもできます。
下書きプレビュー通知と終了ボタンだけは、親のunstyledに関係なく標準デザインを表示します。通知だけ装飾を外す場合はpreviewNotice={{ unstyled: true }}、通知自体を隠す場合はpreviewNotice={false}を指定します。
記事全体のリンクには、クリック領域とキーボードフォーカスを成立させる最小限のCSSを使います。これは見た目のテーマとは別の、操作に必要な処理です。
表示の指定
- 表示項目は
ListItem/ViewItemで明示します。テキスト・画像・HTMLなどの種類は生成スキーマから判断します。 className・styleを各部品に渡せます。<h1>・<div>などのラッパーでレイアウトを組めます。- 日時は
id="publishedAt" format="yyyy/MM/dd HH:mm" timeZone="Asia/Tokyo"。既定のタイムゾーンはUTCです。 - 参照は
id="author.name"。複数参照は値を参照順で表示します。標準の参照展開は2階層までです。 - 未入力の値は表示しません。
fallbackにJSXを渡せます。falseや0は未入力と扱いません。 - リンクは
Listのhref="/blog/{id}"で記事全体に設定するか、内部に<ListLink href="/blog/{id}">読む</ListLink>を置きます。ネストしたリンクを壊さず操作できます。 - フィールドIDは実行時に検証します。親の
apiから子の文字列IDをTypeScriptで推論する機能はありません。
ページ送り・キャッシュ
既定の Pagination はURLを変えず一覧だけを切り替えます。<Pagination mode="url" param="page" /> はURLと連動し、戻る操作にも対応します。List にも searchParams を渡すと、URL指定のページを最初からサーバーで描画します。渡さない場合はブラウザで同期します。複数のURL連動一覧には別々の param を指定してください。
List は limit(1〜100)、offset、filters、orders、q を指定できます。既定は毎回取得し、cache={60} などの秒数を明示した場合だけ初回取得をキャッシュします。ページ送りによる取得と下書き表示は毎回最新です。
ページ送りはSDK内のServer Actionを利用します。APIキーをブラウザへ送らず、サーバーが発行した取得先・条件だけを受け付けます。署名の有効期限は1時間です。期限切れ・キー交換後はページを再読み込みしてください。ページ送りを使うクライアントのキーは GENKO_API_KEY と一致させてください。カスタム fetch / wrapRequest はページ送りには対応しません。静的エクスポート・Edgeランタイムは対象外です。
主なprops
List / View
両方にapi、表示用のchildren、className、style、unstyledを指定できます。表示フィールドは自動選択されません。
| prop | 対象 | 既定値・使い方 |
|---|---|---|
api | 両方 | 生成されたclient.blogなど。Listはリスト形式のみ |
cache | 両方 | false。キャッシュする場合は正の秒数 |
depth | 両方 | 2。参照展開の深さ。0・1・2 |
searchParams | 両方 | Promiseまたは解決済みの値。Viewの下書き判定、ListのURL連動ページ送りに使用 |
id | View | リスト形式では必須、オブジェクト形式では省略 |
notFound | View | false。trueで記事なしをNext.jsの404へ切り替える |
previewNotice | View | プレビュー時に表示。falseで非表示、オブジェクトで位置・装飾を調整 |
limit | List | 10。1〜100の整数 |
offset | List | 0。先頭から読み飛ばす件数 |
orders / filters / q | List | 並び替え・条件・検索 |
href | List | /blog/{id}など、1件全体のリンク先 |
ListItem / ViewItem
| prop | 使い方 |
|---|---|
id | 必須。title、publishedAt、author.nameなど |
fallback | 未入力時の代替JSX |
format | 日時の書式。既定はyyyy.MM.dd。yyyy・MM・dd・HH・mm・ssを使用 |
locale / timeZone | 日時表示。既定はja-JP / UTC |
className / style | サイト側のフィールド装飾 |
テキストを見出しにする場合は<h1><ViewItem id="title" /></h1>のようにHTMLで囲みます。リッチテキストは保存済みHTMLの見出しや段落を表示します。通常のテキストフィールドにHTMLを書いてもHTMLとしては描画しません。
状態表示 / Pagination
Error・Null・Loadingには自由なJSX、またはtemplateを指定します。Viewの404応答はNull、認証・通信などの失敗はErrorの対象です。Listの空配列はNull、取得エラーはErrorになります。
Paginationはmode(既定はlocal)、param(既定はpage)、previousLabel、nextLabelと装飾用のpropsを受け取ります。状態部品とページ送りは親の直下に1つずつ置きます。独自コンポーネントやdivの内側に隠さないでください。
スキーマ同期
npx @genko-me/cli pull# 開発時の任意の自動同期(別ターミナル)npx @genko-me/cli pull --watchschema.ts のAPI一覧も同期するため、API追加時に client.ts を編集する必要はありません。同期対象を限定している場合は pull --select-apis で選択に追加します。--watch は10秒ごとに確認し、変更時だけファイルを更新します。
CLIを使わず手動で導入する
npm install @genko-me/sdk @genko-me/react.env.local に GENKO_API_KEY を設定し、次の2ファイルを作成します。例では管理画面に blog APIと title・body フィールドがあることを想定しています。種類・IDは実際のスキーマに合わせてください。
import { listApi } from '@genko-me/sdk';export type Blog = { title: string; body: string };export const apis = { blog: listApi<Blog>({ fields: [ { id: 'title', type: 'text' }, { id: 'body', type: 'richtext' }, ] }),};import 'server-only';import { createGenko } from '@genko-me/sdk';import { apis } from './schema';export const client = createGenko({ workspace: 'your-workspace', apiKey: process.env.GENKO_API_KEY!, apis,}).apis;後はページから client と部品をimportします。手動導入ではスキーマ変更も自分で反映します。同期を自動化する場合はCLIを使用してください。
低レベルの部品
取得を自分で扱う場合は、従来の RichText(@genko-me/react)と ShareButtons(@genko-me/react/share-buttons)も利用できます。
最終更新: 2026年10月19日