Refactor React code away from direct useEffect usage. Use when Codex needs to review, rewrite, or prevent useEffect in React components, custom hooks, or frontend architecture; diagnose infinite loops or race conditions caused by effects; replace effect-driven state syncing with derived values, event handlers, query libraries, keyed remounts, or a mount-only wrapper such as useMountEffect; or enforce a no-direct-useEffect rule in linting and agent guidance.
Refactor React code away from direct useEffect usage. Use when Codex needs to review, rewrite, or prevent useEffect in React components, custom hooks, or frontend architecture; diagnose infinite loops or race conditions caused by effects; replace effect-driven state syncing with derived values, event handlers, query libraries, keyed remounts, or a mount-only wrapper such as useMountEffect; or enforce a no-direct-useEffect rule in linting and agent guidance.
Use Effect
Inspect the local React patterns before changing code. Prefer the project's existing data-fetching library, lifecycle wrapper, and lint setup over introducing new abstractions.
Treat direct useEffect as a code smell by default. Replace it with clearer control flow unless the code is genuinely synchronizing with an external system on mount or unmount.
Workflow
Locate every direct useEffect in the relevant scope and classify why it exists.
Decide whether the effect is:
deriving state from props or state
fetching data
relaying an action that should happen in response to a user event
synchronizing with an external system on mount
resetting local state when an identity changes
Replace the effect with the narrowest alternative pattern.
Preserve existing project conventions. If the codebase already has useMountEffect, use it instead of raw useEffect(..., []).
Verify behavior by running the relevant tests or targeted checks. Pay special attention to loops, duplicate requests, stale state, and remount semantics.
Replacement Rules
Derive State, Do Not Sync It
If an effect sets state from other props or state, compute the value during render instead.
Also collapse multi-step derived values instead of chaining effects through intermediary state.
Use Data-Fetching Abstractions
If an effect fetches data and then writes it into local state, prefer the project's query or loader abstraction. Reuse the codebase's existing library when present.
If the project does not already use a client-side query library, check whether the fetch belongs in framework loaders, server components, or route-level data APIs before adding one.
Use Event Handlers, Not Effect Relays
If state is only used as a flag to make an effect do work later, move that work into the event handler that caused it.
For true setup and cleanup with external systems, use the project's mount-only wrapper if it exists. Keep this category narrow: DOM integration, subscriptions, widget lifecycle, imperative browser APIs.
If a precondition gates the mount-only effect, prefer conditional rendering so the component mounts only when ready.
if (isLoading) return<LoadingScreen />;
return<VideoPlayer />;
Then let VideoPlayer run mount-only setup once.
Reset with key, Not Dependency Choreography
If the goal is "treat this as a new instance when identity changes", remount with key instead of writing effect logic that tries to reset local state.