mcpField
S
studio-best-practices

studio-best-practices

github.com/supabase開発114.3k158 回インストール今日更新
リポジトリ

studio-best-practices について

Supabase Studio の TypeScript と React を扱う開発者向けのコーディングガイドです。コンポーネント構成、データ取得、状態管理、パフォーマンス、型付け、テストの規約を説明します。

主な機能

  1. 01説明的なブール値の命名
  2. 02コンポーネント構成の指針
  3. 03TanStack Query によるデータ取得
  4. 04ローカル状態とフォームの規約
  5. 05境界検証とテストの指針

活用シーン

  1. 01Studio コンポーネントの整理
  2. 02クエリの読み込み・エラー状態の処理
  3. 03フォーム状態とイベントハンドラーの構成
  4. 04テスト向けの純粋関数の抽出

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/supabase/supabase --skill studio-best-practices

インストール後、Claude Code で/studio-best-practicesを入力して読み込まれたか確認します。

詳細

Studio のベストプラクティス

apps/studio/**/*.{ts,tsx} に適用されます。

ブール値の命名

説明的な接頭辞を使用し、別途保存するのではなく既存の状態から導出します。

  • is — 状態/識別:isLoading、isPaused、isNewRecord
  • has — 所有:hasPermission、hasData
  • can — 能力:canUpdateColumns、canDelete
  • should — 条件付き動作:shouldFetch、shouldRender

複雑な条件は名前付き変数に抽出します。

// ❌ inline multi-condition
{
  !isSchemaLocked && isTableLike(selectedTable) && canUpdateColumns && !isLoading && <Button />
}

// ✅ named variable
const canShowAddButton =
  !isSchemaLocked && isTableLike(selectedTable) && canUpdateColumns && !isLoading
{
  canShowAddButton && <Button />
}

ブール値は導出し、保存しないでください。

// ❌ stored derived state
const [isFormValid, setIsFormValid] = useState(false)
useEffect(() => {
  setIsFormValid(name.length > 0 && email.includes('@'))
}, [name, email])

// ✅ derived
const isFormValid = name.length > 0 && email.includes('@')

コンポーネントの構成

複合コンポーネントとコンポジションのパターンについては、vercel-composition-patterns スキルを参照してください。

コンポーネントは 200~300 行未満に保ちます。次のような場合は分割してください。

  • 複数の独立した UI セクションがある
  • 条件付きレンダリングが複雑である
  • 関連性のない useState 呼び出しが複数ある
  • ひと目で理解しにくい

サブコンポーネントは親と同じディレクトリにまとめます。再エクスポート用のバレルファイルは避けてください。

繰り返し使う JSX パターンは、小さなコンポーネントに抽出します。

データ取得

すべてのデータ取得には TanStack Query(React Query)を使用します。クエリ/ミューテーションのパターンについては studio-queries スキルを、エラー表示の規約については studio-error-handling スキルを参照してください。

ローディング/エラー/成功のパターン

トップレベル:

const { data, error, isLoading, isError, isSuccess } = useQuery(...)

if (isLoading) return <GenericSkeletonLoader />
if (isError) return <AlertError error={error} subject="Failed to load data" />
if (isSuccess && data.length === 0) return <EmptyState />
return <DataDisplay data={data} />

早期リターンを使い、深くネストした条件分岐は避けます。

インライン:

<div>
  {isLoading && <InlineLoader />}
  {isError && <InlineError error={error} />}
  {isSuccess && data.length === 0 && <EmptyState />}
  {isSuccess && data.length > 0 && <DataDisplay data={data} />}
</div>

状態管理

状態は可能な限りローカルに保ち、必要な場合にのみリフトアップします。

複数の useState 呼び出しを使うのではなく、関連するフォームの状態は react-hook-form でまとめます。フォームのレイアウトとコンポーネントの規約については、studio-ui-patterns スキルを参照してください。

// ❌ multiple related useState
const [name, setName] = useState('')
const [email, setEmail] = useState('')

// ✅ grouped with react-hook-form
const form = useForm<FormValues>({ defaultValues: { name: '', email: '' } })

カスタムフック

複雑なロジックや再利用可能なロジックはフックに抽出します。配列ではなくオブジェクトを返します。

// ❌ array return (hard to extend)
return [value, toggle]

// ✅ object return
return { value, toggle, setTrue, setFalse }

イベントハンドラー

  • プロパティのコールバック:on 接頭辞(onClose、onSave)
  • 内部ハンドラー:handle 接頭辞(handleSubmit、handleCancel)

メモ化された子コンポーネントに渡すハンドラーには useCallback を使用し、不要なインラインのアロー関数は避けてください。

条件付きレンダリング

// Simple show/hide
<>{isVisible && <Component />}</>

// Binary choice
<>{isLoading ? <Spinner /> : <Content />}</>

// Multiple conditions — use early returns, not nested ternaries
if (isLoading) return <Spinner />
if (isError) return <Error />
return <Content />

パフォーマンス

本当にコストの高い計算(想定ではなく、計測済みのもの)には useMemo を使用します。すべてをラップするのではなく、計測によって問題が確認された場合、または値をメモ化された子コンポーネントに渡す場合にのみ最適化してください。

TypeScript

プロパティのインターフェースを明示的に定義します。複雑な状態には判別可能なユニオンを使用します。

type AsyncState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error }

as any/as Type による型アサーションは避けてください。境界では zod を使って検証します。

// ❌ type cast
const user = apiResponse as User

// ✅ zod parse
const user = userSchema.parse(apiResponse)
// or safe:
const result = userSchema.safeParse(apiResponse)

テスト

ロジックを .utils.ts の純粋関数に抽出し、網羅的にテストします。テスト戦略全体と判断ツリーについては、studio-testing スキルを参照してください。

コメント