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

no-use-effect

ReactのuseEffectを用途別に見直し、計算・データ取得・イベント処理などに置き換えるスキル。新規実装や既存コードの改修、PRレビューに使えます。

原文原文の説明を見る

Enforce the no-useEffect rule when writing or reviewing React code. ACTIVATE when writing React components, refactoring existing useEffect calls, reviewing PRs with useEffect, or when an agent adds useEffect "just in case." Provides the five replacement patterns and the useMountEffect escape hatch.

実行スコア 未検証

インストール方法を見る

こんなときに便利

  • Reactコンポーネントの新規実装
  • 既存のuseEffectを整理したいとき
  • useEffectを含むPRのレビュー
  • ID変更時に状態を初期化したいとき

日本語での紹介

できること

ReactのuseEffectを目的ごとに分類し、直接呼び出さない実装へ整理します。他の状態から求める値はその場で計算し、データ取得はuseQueryなどのライブラリへ、ユーザー操作への反応はイベントハンドラーへ移します。初回表示時の外部システムとの連携にはuseMountEffect、対象の切り替えに伴う状態の初期化にはkeyを使う、計5つの方針を示します。

こんなときに便利

新しいコンポーネントを書くときや、既存のuseEffectを減らしたいときに向いています。状態を合図に別の処理を動かす実装や、念のため追加された処理をPRレビューで点検する際にも使えます。

使い方の例

  • 「このコンポーネントのuseEffectを用途別に見直して」
  • 「videoIdが変わったら状態を初期化する実装を、keyで整理して」

注意点

useMountEffectは空の依存配列でuseEffectを包む独自の関数です。初回表示時の設定と終了時の解除に適した、依存値が変化しない処理が対象です。検証手順にはBunによる型チェックとテストのコマンドが示されています。

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

含まれるファイル(2)

  • SKILL.md6.6 KB
  • references/you-might-not-need-an-effect.md50.7 KB

SKILL.md(原文)

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

No useEffect

Never call useEffect directly. Use derived state, event handlers, data-fetching libraries, or useMountEffect instead.

Quick Reference

This skill is dervied from the React docs: You Might Not Need an Effect. IMPORTANT: when this skill is invoked you MUST read this post in entirety.

Instead of useEffect for...Use
Deriving state from other state/propsInline computation (Rule 1)
Fetching datauseQuery / data-fetching library (Rule 2)
Responding to user actionsEvent handlers (Rule 3)
One-time external sync on mountuseMountEffect (Rule 4)
Resetting state when a prop changeskey prop on parent (Rule 5)

When to Use This Skill

  • Writing new React components
  • Refactoring existing useEffect calls
  • Reviewing PRs that introduce useEffect
  • An agent adds useEffect "just in case"

Workflow

1. Identify the useEffect

Determine what the effect is doing -- deriving state, fetching data, responding to an event, syncing with an external system, or resetting state.

2. Apply the Correct Replacement Pattern

Use the five rules below to pick the right replacement.

3. Verify

bun --bun run typecheck -- --filter=<package>
bun --bun run test -- --filter=<package>

The Escape Hatch: useMountEffect

For the rare case where you need to sync with an external system on mount:

The implementation wraps useEffect with an empty dependency array to make intent explicit:

export function useMountEffect(effect: () => void | (() => void)) {
  /* eslint-disable no-restricted-syntax */
  useEffect(effect, []);
}

Replacement Patterns

Rule 1: Derive state, do not sync it

Most effects that set state from other state are unnecessary and add extra renders.

// BAD: Two render cycles - first stale, then filtered
function ProductList() {
  const [products, setProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);

  useEffect(() => {
    setFilteredProducts(products.filter((p) => p.inStock));
  }, [products]);
}

// GOOD: Compute inline in one render
function ProductList() {
  const [products, setProducts] = useState([]);
  const filteredProducts = products.filter((p) => p.inStock);
}

Smell test: You are about to write useEffect(() => setX(deriveFromY(y)), [y]), or you have state that only mirrors other state or props.

Rule 2: Use data-fetching libraries

Effect-based fetching creates race conditions and duplicated caching logic.

// BAD: Race condition risk
function ProductPage({ productId }) {
  const [product, setProduct] = useState(null);

  useEffect(() => {
    fetchProduct(productId).then(setProduct);
  }, [productId]);
}

// GOOD: Query library handles cancellation/caching/staleness
function ProductPage({ productId }) {
  const { data: product } = useQuery(['product', productId], () =>
    fetchProduct(productId)
  );
}

Smell test: Your effect does fetch(...) and then setState(...), or you are re-implementing caching, retries, cancellation, or stale handling.

Rule 3: Event handlers, not effects

If a user clicks a button, do the work in the handler.

// BAD: Effect as an action relay
function LikeButton() {
  const [liked, setLiked] = useState(false);

  useEffect(() => {
    if (liked) {
      postLike();
      setLiked(false);
    }
  }, [liked]);

  return <button onClick={() => setLiked(true)}>Like</button>;
}

// GOOD: Direct event-driven action
function LikeButton() {
  return <button onClick={() => postLike()}>Like</button>;
}

Smell test: State is used as a flag so an effect can do the real action, or you are building "set flag -> effect runs -> reset flag" mechanics.

Rule 4: useMountEffect for one-time external sync

Good uses: DOM integration (focus, scroll), third-party widget lifecycles, browser API subscriptions.

// BAD: Guard inside effect
function VideoPlayer({ isLoading }) {
  useEffect(() => {
    if (!isLoading) playVideo();
  }, [isLoading]);
}

// GOOD: Mount only when preconditions are met
function VideoPlayerWrapper({ isLoading }) {
  if (isLoading) return <LoadingScreen />;
  return <VideoPlayer />;
}

function VideoPlayer() {
  useMountEffect(() => playVideo());
}

Use useMountEffect for stable dependencies (singletons, refs, context values that never change):

// BAD: useEffect with dependency that never changes
useEffect(() => {
  connectionManager.on('connected', handleConnect);
  return () => connectionManager.off('connected', handleConnect);
}, [connectionManager]); // connectionManager is a singleton from context

// GOOD: useMountEffect for stable dependencies

useMountEffect(() => {
  connectionManager.on('connected', handleConnect);
  return () => connectionManager.off('connected', handleConnect);
});

Smell test: You are synchronizing with an external system, and the behavior is naturally "setup on mount, cleanup on unmount."

Rule 5: Reset with key, not dependency choreography

// BAD: Effect attempts to emulate remount behavior
function VideoPlayer({ videoId }) {
  useEffect(() => {
    loadVideo(videoId);
  }, [videoId]);
}

// GOOD: key forces clean remount
function VideoPlayer({ videoId }) {
  useMountEffect(() => {
    loadVideo(videoId);
  });
}

function VideoPlayerWrapper({ videoId }) {
  return <VideoPlayer key={videoId} videoId={videoId} />;
}

Smell test: You are writing an effect whose only job is to reset local state when an ID/prop changes, or you want the component to behave like a brand-new instance for each entity.

Component Structure Convention

Computed values come after hooks and local state, never via useEffect:

export function FeatureComponent({ featureId }: ComponentProps) {
  // Hooks first
  const { data, isLoading } = useQueryFeature(featureId);

  // Local state
  const [isOpen, setIsOpen] = useState(false);

  // Computed values (NOT useEffect + setState)
  const displayName = user?.name ?? 'Unknown';

  // Event handlers
  const handleClick = () => { setIsOpen(true); };

  // Early returns
  if (isLoading) return <Loading />;

  // Render
  return <Flex direction="column" gap="lg">...</Flex>;
}

レビュー

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

コメント

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

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

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

0 / 1000 文字

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

同じリポジトリのスキル

agent-browser

無料概要あり

Webページの移動やフォーム入力、クリックをエージェントに任せ、情報抽出や画面保存、操作前後の比較まで行います。ブラウザ作業の自動化やWebアプリの確認に使えるスキル。

  • フォーム入力やクリックを自動化したいとき
  • Webページのテキスト抽出
  • ページのスクリーンショット・PDF保存
humanlayer/humanlayer1.2万2026年10月23日 更新

asd-ste100

無料概要あり

曖昧で読みにくい英文を、語の意味をそろえた短い能動態の文へ書き直すスキル。指示文やツール説明を見直し、修正理由と変更前後を表で確認できます。

  • 別のエージェントへの英文指示の明確化
  • 英語のツール説明やエラー文の簡素化
  • 英語を母語としない読者向けの文章整理
humanlayer/humanlayer1.2万2026年10月23日 更新

better-github-skill

無料概要あり

GitHubのPRの状態、レビューの会話、CI失敗のログを専用スクリプトで収集し、変更の確認状況や未解決の指摘、失敗したジョブとステップを調べるスキル。

  • PRの状態をまとめて確認したいとき
  • 未解決のレビューの会話の確認
  • CIの失敗ジョブとステップの調査
humanlayer/humanlayer1.2万2026年10月23日 更新

bump-version

無料概要あり

リリース時に対象パッケージの基準バージョンを更新し、関連ファイルの同期と生成結果を検証して、コミットからPRブランチへのプッシュまで進めるスキル。

  • リリース用のバージョンを更新したいとき
  • 関連ファイルのバージョン表記の同期
  • プッシュ前の生成バージョン検証
humanlayer/humanlayer1.2万2026年10月23日 更新

calldiff

無料概要あり

Git のコミット間や作業中のコードで、関数の呼び出し構造の違いを確認します。呼び出しツリーの表示や、指定した関数へ至る経路の調査にも使えます。

  • 変更前後の関数呼び出しを比較したいとき
  • ブランチ間の呼び出し構造レビュー
  • 起点から目的の関数への経路調査
humanlayer/humanlayer1.2万2026年10月23日 更新

chrome-devtools-cli

無料概要あり

ターミナルからブラウザのクリックや入力、ページ移動を自動化し、通信やエラー、表示速度も調べられる、Chrome DevToolsのCLI操作を支援するスキル。

  • フォーム入力やページ移動の自動化
  • ページや要素の画面撮影
  • 通信内容やコンソールエラーの調査
humanlayer/humanlayer1.2万2026年10月23日 更新

humanlayer のスキルをすべて見る

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