
Refactor React Effects
FreeStreamline your React useEffect for cleaner code.
Free · Opens the source repo
What Refactor React Effects does
Refactor React Effects is a specialized skill designed to help developers optimize the usage of the useEffect hook in React applications, particularly within the Langfuse frontend codebase. This skill emphasizes the importance of using useEffect only when necessary, specifically to synchronize components with external systems. By following the guidelines provided, developers can avoid unnecessary effects, leading to cleaner, more maintainable code. The skill encourages a thorough understanding of when and why to use effects, ensuring that each effect added to a component serves a clear purpose.
The skill provides a structured approach to refactoring by prompting developers to ask critical questions before adding or retaining an effect. It guides users through a decision-making process that includes identifying the external system involved, understanding the triggers for synchronization, and ensuring proper cleanup to prevent memory leaks. By adhering to these principles, developers can significantly reduce the complexity of their components and enhance performance by minimizing unnecessary renders and state updates.
In addition to the decision rules, the skill outlines a comprehensive workflow for refactoring. This includes establishing behavior boundaries, inventorying existing effects, and refactoring in a methodical manner to maintain user-visible behavior. The emphasis on verifying changes through focused testing and linting ensures that the integrity of the application remains intact throughout the refactoring process. This skill is ideal for developers who are looking to improve their React code quality and maintainability, particularly in large codebases where managing effects can become cumbersome.
Overall, Refactor React Effects is a valuable tool for any developer working with React, especially those involved in maintaining or enhancing the Langfuse frontend. It provides a clear framework for making informed decisions about effect usage, ultimately leading to more efficient and sustainable code practices.
When to use it
Use this skill when adding, reviewing, or removing effects in React components, especially in large codebases.
When not to use it
Avoid this skill for simple components where effects are already well-managed or when dealing with non-React code.
What you can build with it
Optimizing Component Effects
Use this skill to review and refactor components that have multiple `useEffect` hooks, ensuring each effect has a clear purpose.
Cleaning Up Legacy Code
Apply this skill when working on legacy React codebases to identify and remove unnecessary effects, improving maintainability.
Enhancing Performance
Utilize this skill to streamline component behavior by refactoring effects, which can lead to better performance in rendering.
How to install Refactor React Effects
View source1. Install with the skills CLI
npx skills add langfuse/langfuse/refactor-react-effects --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by langfuseRefactor React Effects
Do not add useEffect by default. Use it only to synchronize a component with
a concrete system outside React. If there is no external system, remove the
effect.
Before adding or retaining an effect, answer all of these questions:
- Which external system is being synchronized?
- What starts or updates the synchronization?
- What cleanup, if any, prevents leaks or duplicate subscriptions?
- Why can an event handler, query API, render derivation, conditional mount, or existing integration hook not own the behavior?
If the first question has no concrete answer, do not use an effect.
Required Context
- Read
web/AGENTS.mdand the nearest package guidance before changing web code. - For large features, local Zustand stores, tables, or controller components,
also read
../frontend-large-feature-architecture/SKILL.md. - Read
references/refactoring-patterns.mdbefore implementing a refactor.
Decision Rules
Apply these rules in order:
- Derive during render. Compute values from current props, query data, and client state instead of storing a synchronized copy.
- Gate on required data. If a form or UI cannot initialize correctly
without query data, let a parent own loading/error handling. Mount a child
only after the data exists and pass guaranteed initial values to its lazy
useStateinitializer. - Make reset semantics explicit. Use a
keyto remount for a new entity only when discarding the old local draft is intended. Use an explicit user action for refresh/reset when drafts must not be overwritten silently. - Run actions from events. Put submit, mutation, navigation, notification,
and multi-step async workflows in event handlers,
actions/*.ts, or store actions. Pass a React Query client, mutation callback, or vanilla Zustand store as a dependency; never call React hooks from those actions. - Keep real integration effects. Subscriptions, observers, browser event
listeners, timers, and imperative third-party APIs may need an effect. Make
setup and cleanup symmetrical and keep the effect in a narrow integration
hook or container. In a direct-effect-free module, use a pre-existing,
centrally owned integration hook. Do not create a feature-local wrapper just
to hide
useEffect.
Presume that an effect which writes React or Zustand state from props or query
data is removable. Do not evade the design problem by switching to
useLayoutEffect, suppressing dependency lint, hiding the same synchronization
in a custom hook, or adding an ESLint disable.
Fast Smell Test
Refactor when any of these shapes appear:
useEffect(() => setX(deriveFromY(y)), [y]);- fetch data, then mirror it with
setState; - set a flag, let an effect perform the action, then clear the flag;
- chain effects where one state write triggers the next effect;
- reset local state because an ID or prop changed;
- guard an integration inside an effect when the component could mount only after the precondition is true.
Workflow
1. Establish the Behavior Boundary
Identify the state owner, query owner, user events, external systems, and loading/error states. For a bug fix, add the failing test first and confirm it fails. For a behavior-preserving migration, reuse existing coverage where it protects the relevant behavior; add focused coverage only for a meaningful behavior risk such as draft preservation, entity changes, refetches, submits, or cleanup. Do not add tests that inspect source code or merely assert that a hook is absent. Use behavior tests and the effect inventory instead.
2. Inventory Every Effect
Search the full target module, including tests and stories:
rg -n '\b(use(?:Layout)?Effect|React\.use(?:Layout)?Effect)\b' 'web/src/features/<feature>'
Classify every result as:
- render derivation;
- query-to-local-state initialization;
- client/server state synchronization;
- user-event or async workflow;
- external-system integration;
- test-only harness behavior.
Do not refactor from a raw count alone. Record what triggers each effect, what it writes or controls, and the replacement pattern.
3. Refactor One Semantic Seam at a Time
Prefer this order:
- replace redundant state with pure derivation;
- split data-owning parents from stateful children;
- move event-driven work to handlers or external actions;
- isolate unavoidable integrations in narrow hooks;
- remove dead state, guards, dependencies, and imports.
Keep user-visible behavior stable. Avoid bundling unrelated file moves, visual changes, and state architecture changes into the same slice.
4. Complete a Submodule Migration
Repeat the inventory after each slice. Before declaring a submodule clean:
- account for every original effect;
- confirm no effect merely moved behind a wrapper hook;
- confirm refetches do not overwrite local edits;
- confirm entity changes have deliberate preserve/reset semantics;
- confirm complex actions are callable without rendering the feature;
- document any real external integration effect that remains outside the refactoring target.
Do not add or modify effect-specific ESLint rules or pre-commit checks as part of this workflow. Treat enforcement policy as separate, explicitly requested work.
5. Verify
Run, at minimum:
- focused client tests for the changed behavior;
- ESLint on the migrated path, then
pnpm --filter web run lint; - type checking when state or action interfaces changed;
- a real-browser review for user-visible flows, using seeded data where applicable;
- the effect inventory again to prove the intended scope is clean.
Report the exact command summary lines and any retained effects with their external-system rationale.
Output Format
Return valid Markdown. For module audits, include a compact table with the effect location, classification, replacement, and status. Check headings, lists, links, tables, backticks, and code fences for valid Markdown syntax before returning the report.
Frequently asked questions about Refactor React Effects
Similar skills
React Composition Patterns
Streamline your React component architecture with proven patterns.
Pester Should Migration
Easily convert Pester v5 assertions to v6 syntax.
Radix to Base UI Migration
Seamlessly migrate React components from Radix UI to Base UI.
Migrate Next.js to Vinext
Seamlessly transition your Next.js projects to Vinext.
WinUI 3 Migration Guide
Streamline your UWP to WinUI 3 migration process.
Refactor
Enhance code maintainability without altering behavior.
