本文へ移動
cccskills
無料GitHub で公開日本語紹介

data-fetching-architecture

SWRを使うデータ取得の設計や、読み込み・エラー表示、キャッシュ更新、既存のuseEffect fetchの移行方法を案内する開発スキルです。

原文原文の説明を見る

Use for client APIs, SWR hooks, cache invalidation, async errors, useEffect migration, home first paint and persistent caches.

lobehub/lobehubスター 83,506(GitHub 83,506 + cccskills 0)

実行スコア 未検証

インストール方法を見る

こんなときに便利

  • コンポーネントの取得処理をストアへ移したいとき
  • 更新後の古いキャッシュを直したいとき
  • 読み込み・空・エラー表示を整理したいとき

日本語での紹介

できること

クライアント側のデータ取得を、サービス、ストアのフック、コンポーネントに分けて設計する方法を案内します。読み取りには useClientDataSWR を使い、API呼び出しはサービスに置きます。キャッシュキーの共有、書き込み後の更新、保留中の状態管理、初回読み込み・空データ・エラーの区別も扱います。useEffect 内での取得やコンポーネント状態への重複保存を、ストアフックとセレクターを使う形に移行する際にも利用できます。ローカルコピーから表示する一覧・詳細にはReplicaの同期方法を示します。

こんなときに便利

取得後の表示が古い、読み込み中のままになる、初回エラーが空表示に見えるといった問題を調べるときや、取得処理の置き場所を整理したいときに役立ちます。

使い方の例

  • 「このコンポーネントの取得処理をストアのSWRフックに移して」
  • 「更新後に一覧が古いままになる原因を調べて」
  • 「初回エラーと空の結果を正しく表示する方法を確認して」

注意点

LobeHubの既存ラッパーやコード構成に沿って実装します。SWRの既定動作を前提にせず、実際のラッパー設定を確認します。

この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。

資料チェック

SKILL.md の記述から、注意が要る操作と導入の前提を AI が確認しました。点数は実際に動かした結果(実行検証)だけで付けています。

安全面送信・削除・コマンド実行などの扱いが明示されているか
A良好失敗時の楽観更新の復元や削除の扱いを明記している。
導入のしやすさ必要なツールや API キーが少ないか、書かれているか
B一部不足SWRとLobeHubのラッパー構成を前提とするが導入手順はない。

点数には入れていません。 2026年10月26日 時点で AI(OpenAI Codex)が判定しました。目安なので、入れる前に原文も確認してください。

評価が違うと思ったら、見直しを依頼する

どの項目が、なぜ違うと思うかを書いてください。ログインは不要です。内容を SKILL.md と照らし合わせて評価を作り直し、この欄に反映します。

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

含まれるファイル(3)

  • SKILL.md7.0 KB
  • references/home-first-paint.md3.9 KB
  • references/walkthrough.md3.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

LobeHub Data Fetching Architecture

Component → Store useFetchXxx hook → Service → lambdaClient
          ← SWR request state + store data ← response

Layer boundaries

  • Services in src/services/ own API calls: .query() for reads, .mutate() for writes. Export a service instance per domain; components and stores do not call lambdaClient directly.
  • Store read hooks use useClientDataSWR and return its SWR response, including error and mutate. Sync successful results into the store through the wrapper's supported callback (onSuccess, or onData for the sync wrapper).
  • Server lists and details that paint from a local copy go through @/libs/replica instead: the store's useFetchXxx returns slice.useSync(params) (flags only) and the engine writes the store. See the Replica section of zustand.
  • Components call these hooks and read store data through selectors. Do not fetch in useEffect or duplicate server data in component useState.
  • Use useFetchXxx for read hooks and refreshXxx for cache invalidation.
  • For list/detail types, maps, reducers, and shared type sources, use Zustand data structures. For store layout and action classes, use zustand.

Home First Paint and Persistent Caches

When changing home/sidebar first paint or persisted display data, read references/home-first-paint.md. It covers avoiding flicker, reusing persistence, and the user displaySnapshot.ts boundary.

Cache keys and refresh

Reuse the domain key factory in src/libs/swr/keys.ts; define a shared key if the domain has none. Include every parameter that changes the response: entity or parent id, filters, sort, and pagination. Read and refresh must construct the same key.

Import useClientDataSWR and mutate from @/libs/swr, keeping the application's workspace/cache handling. Return a null key when a required id is absent; passing undefined to a store hook only disables fetching if that hook maps it to null.

For example, inside an action class:

useFetchBenchmarks = () =>
  useClientDataSWR(evalKeys.benchmarks(), () => agentEvalService.listBenchmarks(), {
    onSuccess: (data) => {
      this.#set({ benchmarkList: data, benchmarkListInit: true });
    },
  });

refreshBenchmarks = async () => {
  await mutate(evalKeys.benchmarks());
};

Read the current benchmark action for store wiring and the SWR wrappers for their actual options. These links locate implementation; they do not make every existing call site a template to copy unchanged.

Hooks that share a known parent id can run together. If one request needs a value returned by another, keep its key null until that value exists. Do not assume the application wrapper uses upstream SWR's default deduplication interval.

For lists cached separately under multiple parents, see parent-keyed lists. Ordinary flat lists need no extra layer.

Mutations

  • Call the service, then refresh affected list/detail keys and any related domain whose response changed. Await refresh when subsequent UI behavior depends on it.
  • Keep pending flags in store state and clear them in finally. Use per-id state for row updates/deletes so unrelated rows remain usable; create can use a separate flag because no persistent id exists yet.
  • For optimistic writes on replica data, use slice.optimistic / entity.optimistic; a rejected call rolls back on its own, deletes included.
  • For optimistic create/update on legacy stores, use the store's reducer/dispatch convention and restore or revalidate affected state if the service fails. Do not leave a temporary row or a successful-looking edit after rejection. Delete only after server success there: a hand-written reducer has no rollback base.
  • Let failures reach the caller's error UI; a finally block clears pending state but does not by itself recover an optimistic write.

Render loading, errors, and settled data

Consume the read hook's SWR response. Success-only flags such as isInit, missing map entries, and data ?? [] cannot distinguish an initial request failure from loading or empty results.

Use AsyncBoundary for standard loading/error/empty/data surfaces; use AsyncError for custom layouts and inline failures. Pass the original SWR data to the boundary: undefined means no successful result, whereas [] is a settled empty result.

Replica useSync returns no data. Feed AsyncBoundary its error and a settled signal from the store entry (data={isListInit || undefined}, where the selector is entry !== undefined); see src/features/Pages/PageLayout/Body/index.tsx.

const BenchmarkList = () => {
  const useFetchBenchmarks = useEvalStore((s) => s.useFetchBenchmarks);
  const benchmarks = useEvalStore((s) => s.benchmarkList);
  const { data, error, isLoading, mutate } = useFetchBenchmarks();

  return (
    <AsyncBoundary
      data={data}
      empty={<EmptyState />}
      error={error}
      isEmpty={data?.length === 0}
      isLoading={isLoading}
      onRetry={() => {
        void mutate();
      }}
    >
      <BenchmarkCards items={benchmarks} />
    </AsyncBoundary>
  );
};

The example's EmptyState and BenchmarkCards stand for the surface's existing renderers. Follow these distinctions when adapting it:

  • Show first-load errors before empty / NotFound / zero-value defaults. Do not put an error branch after if (!map[id]) return <Skeleton />; failure may never fill the map.
  • Preserve settled content during background revalidation failures, including a successfully loaded empty list. A retry in flight should show pending feedback.
  • In a fetched + static list, use the fetched slice's request state before combining rows. Static rows must not hide a failed request.
  • For infinite scroll, keep a per-bucket loadMoreError and show an inline Retry row. Suspend observer-triggered retries while that error is unresolved.
  • A closed modal or absent id disables a request; it is not evidence of a missing record.

Migrating an existing fetch

Move the API call into its service and the request into a store SWR hook. Reuse the existing state shape and action organization unless they need to change for the task. Replace the component's effect/local fetch state with that hook and selectors, then connect error, retry, and pending feedback. Refresh the same cache key after writes.

Check initial failure, retry, settled-empty results, background failure, and switching ids against the surface being changed. For stale data, compare read/refresh keys and the store bucket they update; for stuck loading, inspect rejected requests as well as success callbacks. Do not add a second fetch or another loading flag to mask the cause.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

acceptance

無料概要あり

実際の製品を操作して、利用者が確認できる動作証拠を集め、検証計画に沿った受け入れレポートとして公開するスキルです。

  • 変更後の製品動作を実地で検証したいとき
  • 画面キャプチャなどの証拠を集めたいとき
  • 検証計画とレポートを作成したいとき
lobehub/lobehub8.4万2026年10月26日 更新

add-model-provider

無料概要あり

LobeHubにAIモデルプロバイダーを追加し、実行時連携からモデル表示、設定、ブランド表記、文書化、動作確認まで進めるスキルです。

  • 新しいAIモデルプロバイダーを追加したいとき
  • プロバイダーの設定手順や説明文を更新したいとき
  • 既存プロバイダーへのモデル追加要件を見極めたいとき
lobehub/lobehub8.4万2026年10月26日 更新

add-setting-env

無料概要あり

ユーザー設定の初期値をサーバー側の環境変数で切り替えるため、型定義や設定の組み立て、ユーザーストアへの反映、環境変数の例と説明書きを追加する手順です。

  • 設定の初期値を環境変数で変えたいとき
  • 設定項目をサーバー設定に追加したいとき
  • 環境変数の例と説明を更新したいとき
lobehub/lobehub8.4万2026年10月26日 更新

agent-runtime-hooks

無料概要あり

エージェント実行中の各段階をフックで監視し、ツール呼び出しの模擬・制御や人の承認、圧縮、サブエージェント処理に介入する仕組みを扱います。

  • エージェントの実行状況を記録したいとき
  • ツール結果をテスト用に模擬したいとき
  • Webhookでツール実行を許可・拒否したいとき
lobehub/lobehub8.4万2026年10月26日 更新

agent-signal

無料概要あり

イベントを起点にエージェントのバックグラウンド処理を組み立て、ソース・シグナル・アクション・ポリシーの役割分担や非同期連携を実装するためのスキルです。

  • イベント起点の処理を追加したいとき
  • バックグラウンド処理を非同期化したいとき
  • 重複実行を防ぐ仕組みを整えたいとき
lobehub/lobehub8.4万2026年10月26日 更新

agent-testing-bot

無料概要あり

DiscordやSlackなどの実際のチャットアプリでボットにメッセージを送り、応答を画面で確認する受け入れテストを行うスキルです。

  • 実際のDiscordでボット応答を確かめたいとき
  • SlackやTelegramの会話経路をテストしたいとき
  • macOSアプリ上の操作結果を画面で記録したいとき
lobehub/lobehub8.4万2026年10月26日 更新

lobehub のスキルをすべて見る

このスキルの問題を報告する