mcpField
W
writing-kea-logics

writing-kea-logics

github.com/posthog開発40.5k137 回インストール今日更新
リポジトリ

writing-kea-logics について

PostHog のフロントエンド開発者向けに、kea の状態ロジックの規約をまとめたスキルです。状態の選択、React との接続、型生成を扱い、一般的なパターンも参照できます。

主な機能

  1. 01kea ロジックの規約
  2. 02状態コンテナの選択ガイド
  3. 03React コンポーネント接続パターン
  4. 04インライン型生成の手順
  5. 05一般的なパターンの索引

活用シーン

  1. 01kea ロジックファイルの新規作成や変更
  2. 02React hooks を使うコードのレビュー
  3. 03単一ロジックの型再生成
  4. 04状態変更に使うビルダーの選択

インストール

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

$npx skills add https://github.com/posthog/posthog --skill writing-kea-logics

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
anti-patterns.md
connecting-logics.md
forms.md
keyed-logics.md
loading-data.md
persisting-state.md
polling.md
reacting-to-changes.md
routing.md
state-decision.md
testing.md

詳細

kea ロジックの書き方

PostHog はフロントエンドの状態コンテナとして kea を使用しています。ほとんど すべての非自明なビジネスロジックは React ではなく *Logic.ts / *Logic.tsx ファイルに 置かれます。keajs.org のドキュメントが扱っているバージョンより先行した kea のプレリリースを 使用している可能性があります。迷ったときは、固定されているバージョンを pnpm-workspace.yaml で 確認してください。

このスキルは、上流の kea ドキュメント に加えて、PostHog 固有の規約をまとめたものです。 ビルダーのシグネチャについて迷ったときは、上流のドキュメントを参照してください。 使うべきかどうか迷ったときは、ここを読んでください。

このスキルを使う場面

  • 新しい *Logic.ts / *Logic.tsx ファイルを作成するとき
  • 既存のロジックにビルダー(actions、reducers、selectors、listeners、loaders、forms)を追加するとき
  • ある状態に対して reducer と selector と cache と loader のどれを選ぶか判断するとき
  • React コンポーネントをロジックに接続するとき
  • kea ロジックを導入または変更する PR をレビューするとき
  • ロジックのほうがより慣用的である箇所で React フックを使用しているコードをレビューするとき

併用するスキル(重複させないこと)

  • using-kea-disposables — setInterval、addEventListener、 その他クリーンアップが必要なあらゆるリソース。

作業がこれと重なる場合は、先に併用スキルを読んでください。

基本原則

  1. ビジネスロジックはコンポーネントではなくロジックに置きます。 CLAUDE.md に明記されています。「kea ロジックファイルがある場合は、すべての ビジネスロジックをそこに書き、React フックは可能な限り避けてください。」フックはビューの関心事のためにあります。

  2. 1 つの概念につき、1 つの信頼できる情報源。 アクション駆動の reducer、 派生 selector、非同期 loader のうち、必ず 1 つだけを選んでください。同じ値を複数の場所に ミラーしないでください。

  3. kea-subscriptions よりも listeners を優先してください。 サブスクリプションは、ディスパッチのたびに 再実行される redux サブスクリプションをインストールするため、計測できるほど遅くなります。代わりに、 値を変更したアクションをリッスンしてください。詳しくは references/reacting-to-changes.md を参照してください。

  4. 生成された型が契約です。 すべてのロジックには、kea() 呼び出しの上にインラインで生成された MakeLogicType ブロックがあります。ロジックの型はロジックのソースファイルからインポートし、 別の *LogicType.ts ファイルからは決してインポートしないでください。

  5. クリーンアップが必要なリソースは cache.disposables を経由します。 using-kea-disposables スキルを参照してください。

一目でわかる構造

import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea'
import { loaders } from 'kea-loaders'

import * as api from 'products/foo/frontend/generated/api'

export interface FooLogicProps {
  fooId: string
}

// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
export interface fooLogicValues {
  name: string
  nameUpper: string
}

// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
export interface fooLogicActions {
  setName: (name: string) => { name: string }
}

export type fooLogicType = MakeLogicType<fooLogicValues, fooLogicActions, FooLogicProps>

export const fooLogic = kea<fooLogicType>([
  props({} as FooLogicProps),
  key((props) => props.fooId),
  path((key) => ['scenes', 'foo', 'fooLogic', key]),
  connect(() => ({ values: [teamLogic, ['currentTeamId']] })),
  actions({ setName: (name: string) => ({ name }) }),
  loaders(({ props }) => ({
    foo: [null as Foo | null, { loadFoo: async () => api.foosRetrieve(props.fooId) }],
  })),
  reducers({ name: ['', { setName: (_, { name }) => name }] }),
  selectors({ nameUpper: [(s) => [s.name], (name): string => name.toUpperCase()] }),
  listeners(({ actions }) => ({
    loadFooSuccess: () => {
      /* ... */
    },
  })),
  afterMount(({ actions }) => {
    actions.loadFoo()
  }),
])

慣例的なブロックの順序: props → key → path → connect → actions → forms → loaders → reducers → selectors → sharedListeners → listeners → subscriptions(まれ)→ windowValues → urlToAction / actionToUrl → afterMount / propsChanged / beforeUnmount。

これらすべてが必要になることはほとんどありません。典型的には 6 つほどのブロックです。ロジックが 実際に使用するものを選び、残りは省いてください。

判断フロー — 始める前に適切なコンテナを選ぶ

kea のバグのほとんどは、ある状態に対して誤ったコンテナを選ぶことから生じます。ビルダーに 手を伸ばす前に、これを順に検討してください:

  1. HTTP 呼び出しから取得するものですか? loader を使用してください。
  2. 他の状態から計算できますか? selector を使用してください。
  3. アクションがそれを変更し、変更時に UI が再レンダリングされる必要がありますか? reducer を使用してください。
  4. タイマー、リスナー、その他破棄可能なリソースですか? cache.disposables を使用してください — using-kea-disposables を参照してください。

cache.foo は UI が決して読まない一時的なフラグのための逃げ道です。最初にではなく、 最後に手を伸ばしてください。詳細な内訳については references/state-decision.md を参照してください。

パターンインデックス

各リファレンスは、1 つのジョブ・トゥ・ビー・ダンについて、パターンの形、なぜそれが適切な形なのか、そしてトレードオフを説明しています。リファレンス内のファイル引用は「現在の実例」であり、時間の経過とともに古くなるため、パターン自体が信頼できる情報源です。

やりたいこと読むべきドキュメント
reducer / selector / cache / loader のどれを選ぶか判断するreferences/state-decision.md
API からデータを読み込むreferences/loading-data.md
エンドポイントをポーリングする、または一定間隔で更新するreferences/polling.md
フォームを構築するreferences/forms.md
状態を URL と同期するreferences/routing.md
リロードをまたいで状態を永続化するreferences/persisting-state.md
値の変化に反応するreferences/reacting-to-changes.md
1 つのロジックを複数インスタンスで持つreferences/keyed-logics.md
ロジック間またはコンポーネントのサブツリー間で状態を共有するreferences/connecting-logics.md
ロジックをテストするreferences/testing.md
見ただけで変換すべきとわかるパターンを認識するreferences/anti-patterns.md

型と typegen

import { MakeLogicType, kea } from 'kea'

// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
export interface fooLogicValues {
  name: string
}

// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
export interface fooLogicActions {
  setName: (name: string) => { name: string }
}

export type fooLogicType = MakeLogicType<fooLogicValues, fooLogicActions>
export const fooLogic = kea<fooLogicType>([...])

インラインの型ブロックは kea-typegen 3.8.3 によって生成されます。コマンド:

  • pnpm --filter=@posthog/frontend typegen:watch — ロジックを書いている間のウォッチモード
  • pnpm --filter=@posthog/frontend typegen:write — 一度だけ書き込む
  • pnpm --filter=@posthog/frontend typegen:check — CI での整合性チェック
1 つのロジックを反復開発する

コードベース全体に対する完全な typegen は遅いです。1 つのロジックを反復開発しているときは、typegen をそのファイルに限定してください:

# Regenerate the type for one logic
pnpm --filter=@posthog/frontend typegen:file frontend/src/scenes/foo/fooLogic.ts

ロジックを書いている間はこのループを使用してください。現在の tsgo はプロジェクト設定とファイル引数の併用をサポートしていないため、最後に typegen:check と typescript:check を完全に実行して、他に何も壊れていないことを確認してください。

別の *LogicType.ts ファイルを作成したりインポートしたりしないでください。ロジックを変更して typegen を再実行することで、インラインで生成されたブロックが信頼できる情報源であり続けます。

キー付きロジックでは、エクスポートに明示的に型注釈を付けてください: export const fooLogic: LogicWrapper<fooLogicType> = kea<fooLogicType>([...])。

迷ったときは

  • 新しいパターンを発明する前に、上記の該当するリファレンスを読んでください。
  • ビルダーのシグネチャについては、上流の keajs.org ドキュメントを読んでください。
  • リポジトリ内で *Logic.ts の中からビルダー名を検索してください — 何百もの動作する例があり、規約は安定しています。
  • 状態管理の判断では、他の場所のコードを削除できる選択肢を優先してください。

コメント