claude/skills/jotai-react-mastery/SKILL.md
JotaiとReact Suspense/Transitionを組み合わせたモダンな状態管理・非同期処理のベストプラクティス集。uhyo氏の「jotaiによるReact再入門」に基づく。
npx skillsauth add kazuph/dotfiles jotai-react-masteryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Jotaiを用いたReactアプリケーション設計、特にSuspense、Concurrent features(Transition)、非同期処理、エラーハンドリングに関するベストプラクティスを提供するスキルです。 「jotaiによるReact再入門」の内容をベースに、宣言的UIの原則に従った実装パターンを提示します。
useTransition を用いたUX改善(ちらつき防止、ペンディング表示)jotai-eager を用いたパフォーマンス最適化atomでステートを定義し、useAtomで利用する。useStateの役割を分割・拡張する。Suspenseを正しく動作させるため、Promiseはコンポーネント内(useEffectやuseMemo内)ではなく、**コンポーネントの外(Atom)**で管理する。
// コンポーネント外でPromiseを保持する
const userAtom = atom(async () => {
const user = await fetchUser();
return user;
});
// コンポーネント内
const UserProfile = () => {
// atomの値がPromiseの場合、解決するまで自動的にサスペンドする
const user = useAtomValue(userAtom);
return <div>{user.name}</div>;
};
IDごとのデータ取得には以下の2パターンを使い分ける。
パラメータ依存atom(単一のパラメータのみ扱う場合)
const userIdAtom = atom<string | null>(null);
const userAtom = atom(async (get) => {
const id = get(userIdAtom);
if (!id) return null;
return fetchUser(id);
});
Atom Family(複数のパラメータを同時に扱う、キャッシュが必要な場合)
import { atomFamily } from 'jotai/utils';
const userAtomFamily = atomFamily((id: string) =>
atom(async () => fetchUser(id))
);
const UserProfile = ({ id }) => {
const user = useAtomValue(userAtomFamily(id));
// ...
};
データの再取得(Refetch)は「手続き的な再実行」ではなく、「UIバージョン(キー)の更新によるステートの再評価」として実装する。これは「データ取得もUIの計算の一部」という宣言的UIの思想に基づく。
import { atom, type Getter } from "jotai";
function createReloadableAtom<T>(getter: (get: Getter) => T) {
const refetchKeyAtom = atom(0);
return atom(
(get) => {
get(refetchKeyAtom); // 依存を作成
return getter(get);
},
(get, set) => {
// バージョンを更新して再評価をトリガー
set(refetchKeyAtom, (c) => c + 1);
}
);
}
// 使用例
const userListAtom = createReloadableAtom(async () => fetchUsers());
// コンポーネント内での使用
const UserList = () => {
const users = useAtomValue(userListAtom);
const reload = useSetAtom(userListAtom); // 実行すると再取得
// ...
};
Suspenseによるフォールバック表示(ローディング)のちらつきを防ぎ、「古いUI」を維持しつつ裏で読み込む。
useTransition / startTransition: ステート更新をラップして「優先度の低い更新」とする。isPending を利用して、古いUIが表示されている間に「読み込み中...」などのフィードバックを即座に返す。const [isPending, startTransition] = useTransition();
const handleChange = (nextId) => {
startTransition(() => {
setUserId(nextId); // この更新によるサスペンドはフォールバックを表示せず、古いUIを維持する
});
};
// UI側: isPendingを用いて応答性を確保
<div style={{ opacity: isPending ? 0.5 : 1 }}>
<Suspense fallback={<Spinner />}>
<UserProfile id={userId} />
</Suspense>
</div>
Suspense に key を与えるか、条件付きレンダリングで新しい Suspense インスタンスを生成することで、強制的にフォールバックを表示させる。初期ロード時は非同期(Promise)だが、キャッシュがある場合は同期的に値を返したい場合に jotai-eager を使用する。無駄なサスペンド(一瞬のLoading表示)を防ぐ。
import { eagerAtom } from 'jotai-eager';
// 内部状態がnull(初期状態)のときだけ非同期、それ以外は同期
const valueAtom = eagerAtom((get) => {
const internalVal = get(internalAtom);
if (internalVal !== null) {
return internalVal; // 同期的に返す
}
// 非同期読み込み
const data = get(asyncDataAtom);
return data; // Promiseになる可能性がある
});
eagerAtom は、getでPromiseを取得したときのみ自身もPromiseを返し、それ以外は値をそのまま返す(同期)。
非同期atomのPromiseがrejectされた場合、コンポーネントでエラーがスローされる。
react-error-boundary の利用を推奨。resetErrorBoundary) と、Atomの再読み込み (reloadAtom) をトランジション内で同時に行う。const UserListErrorFallback = ({ error, resetErrorBoundary }) => {
const reloadUserList = useSetAtom(userListAtom); // createReloadableAtomで作成したもの
const handleRetry = () => {
startTransition(() => {
resetErrorBoundary(); // Error Boundaryの状態リセット
reloadUserList(); // Atomの再評価トリガー
});
};
return (
<div>
<p>Error: {error.message}</p>
<button onClick={handleRetry}>Retry</button>
</div>
);
};
tools
X (Twitter) API read-only CLI. Bookmarks retrieval, tweet search, engagement analytics (likes/RT aggregation), mentions, user lookup. Use when: reading X bookmarks, searching tweets, aggregating likes/retweets, checking mentions, looking up users. Triggers: bookmark, bookmarks, X search, Twitter search, likes count, RT count, engagement, tweet analytics.
testing
単体テスト方針の要約。Kiro流で使うときは本文を必ず参照・展開する。
tools
Send prompts to other AI CLIs (Codex, Claude Code) running in sibling tmux panes and receive results back. Use this skill when the user asks to send a question or task to Codex or another Claude Code instance in a tmux pane. Handles pane discovery, CLI startup if needed, prompt delivery with proper Enter timing, delivery verification, and result return via tmux send-keys.
data-ai
TAKT ピースエンジン。Agent Team を使ったマルチエージェントオーケストレーション。ピースYAMLワークフローに従ってマルチエージェントを実行する。