Claude-skill-registry-data manage-client-state

クライアント状態をグローバル/URL状態で型安全に管理します。サイドバーやフィルタはuseSWRImmutable、ページネーションはnuqs。

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry-data
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/manage-client-state" ~/.claude/skills/majiayu000-claude-skill-registry-data-manage-client-state && rm -rf "$T"
manifest: data/manage-client-state/SKILL.md
source content

クライアント状態管理スキル

クライアントサイドの状態管理の全ワークフローを提供します。

いつ使うか

このスキルは以下の場合に使用してください:

  • グローバルUI状態の管理(サイドバー、テーマ)
  • URL状態の管理(ページネーション、フィルタ、検索、タブ)
  • Contextプロバイダーを避けたい場合
  • 状態をURLに永続化したい場合

manage-swr-data との使い分け

manage-client-state(このスキル): クライアント内で完結する UI 状態

  • サイドバー開閉、テーマ、モーダル表示
  • URL 同期(ページネーション、検索、フィルタ)
  • ブラウザストレージ(localStorage)

manage-swr-data: サーバーから取得するデータ

  • API レスポンスのキャッシュ
  • データ取得・変更(GET/POST/PUT/DELETE)
  • バックグラウンド再検証

判断基準: サーバーから取得するデータは manage-swr-data、クライアント内で完結する状態は manage-client-state を使用します。

状態管理の選択

要件手段
URL復元(戻る/共有)nuqspage, query, filter
localStorage永続化useSWRImmutable + useEffecttheme, settings
セッション内のみuseSWRImmutablemodal, selectedRows

ワークフロー

1. グローバル状態(useSWRImmutable)

'use client'

import useSWRImmutable from 'swr/immutable'

export function useSidebar() {
  const { data, mutate } = useSWRImmutable('sidebar-open', null, {
    fallbackData: true
  })

  return {
    isOpen: data ?? true,
    toggle: () => mutate(!data, false)
  }
}

// コンポーネントでの使用
export function Sidebar() {
  const { isOpen, toggle } = useSidebar()

  return (
    <aside className={isOpen ? 'open' : 'closed'}>
      <button onClick={toggle}>切り替え</button>
    </aside>
  )
}

2. URL状態(nuqs)

Server Component(パース)

import { createSearchParamsCache, parseAsInteger } from 'nuqs/server'
import type { PageProps } from 'next/types'

export const searchParamsCache = createSearchParamsCache({
  page: parseAsInteger.withDefault(1),
})

export default async function Page({ searchParams }: PageProps<'/users'>) {
  const { page } = await searchParamsCache.parse(searchParams)

  const users = await fetchUsers({ page })

  return <UserList users={users} page={page} />
}

Client Component(状態)

'use client'

import { useQueryStates, parseAsInteger, parseAsString } from 'nuqs'

export function UserFilters() {
  const [{ page, query }, setFilters] = useQueryStates({
    page: parseAsInteger.withDefault(1),
    query: parseAsString.withDefault(''),
  })

  return (
    <input
      value={query}
      onChange={(e) => setFilters({ query: e.target.value, page: 1 })}
    />
  )
}

重要ルール

グローバル状態

  • useSWRImmutable
    を使用(
    useSWR
    ではない)
  • デフォルト値に
    fallbackData
    を設定
  • 再検証なしで更新するには
    mutate(newValue, false)
    を使用
  • サーバーデータには使用しない

URL状態

  • Server Componentでは
    createSearchParamsCache
    を使用
  • Client Componentでは
    useQueryStates
    を使用
  • パーサー(
    parseAsInteger
    parseAsString
    など)を使用
  • 常に
    .withDefault()
    でデフォルト値を設定

詳細パターン

詳細な実装パターンについては references を参照してください: