Treat an Effect as a resource lifecycle
An Effect connects a component to something outside React, such as a subscription, timer or network request. That connection has a beginning and an end. If the component's relevant inputs change, the old work may need to stop before the replacement becomes authoritative. A result arriving later is not necessarily the result the user currently needs.
Consider a search box. A request for one phrase can finish after a newer request for another phrase. Updating the screen with whichever response arrives last can show the wrong data. This is a request-order problem, not a reason to remove all asynchronous behavior or to copy every incoming value into additional state.
Setup: define who owns the external work
For each Effect, list the external resource, reactive dependencies, setup operation and corresponding cleanup. A subscription needs an unsubscribe action; a timer needs cancellation; a request needs a clear rule for whether its result remains relevant. Keep business authorization on the server even when the client manages its own request lifecycle correctly.
The React documentation specifies cleanup before setup for changed dependencies, and cleanup on unmount. Development Strict Mode also exercises an additional setup and cleanup cycle. Treat this as an opportunity to expose incomplete resource ownership. Do not remove the development check merely to hide duplicate logs. Review whether the task belongs in an Effect at all: rendering derived values and handling a direct user event often need different code paths.
Illustrative incident: the older search wins
An illustrative support console sends a search when the selected customer changes. A slow first response arrives after the second selection and overwrites the newer details. The incident becomes more confusing when development logs also show extra setup activity. This scenario is educational and does not describe a real customer's data exposure.
Use artificial response delays with synthetic customer records. Capture a request identifier, selected input revision and whether the response was accepted or discarded. Avoid logging the full response when a small correlation field can establish the ordering.
Troubleshooting: separate ordering from duplication
| Observation | Evidence | Boundary to inspect |
|---|---|---|
| Old result replaces new result | Input revision and request completion order | Is stale work still allowed to commit state? |
| Events multiply after navigation | Active subscriptions and cleanup calls | Is every registration removed? |
| Effect repeats without input changes | Dependency identity and state updates | Does setup create a feedback loop? |
| Extra setup appears only in development | Strict Mode and cleanup symmetry | Is lifecycle testing revealing a leak? |
Do not assume that aborting a fetch reverses an operation already accepted by the server. Cancellation of client interest and cancellation of a server-side business mutation are different contracts. A write may need an explicit job status or idempotency design.
Corrective action with explicit relevance
Make cleanup symmetrical with setup. Remove the exact listener or subscription that was registered, clear the timer that was created, and release the resource belonging to that Effect instance. For data loading, use an appropriate cancellation mechanism and a current-request guard where needed so late results cannot update an obsolete view.
Declare dependencies accurately rather than suppressing checks to keep an Effect quiet. Stabilize unnecessary object or function dependencies through a deliberate design, not by concealing actual inputs. Where a framework or established data-loading library owns fetching, follow its lifecycle instead of maintaining a second competing cache and cancellation mechanism inside the component.
Verification, SLO and SOP
Test rapid input changes, an unmount before completion, a failed request, reconnecting subscriptions and the development setup-cleanup cycle. Observe the visible result and active resource count, not only the absence of a console warning. Confirm that the loading and error states belong to the current request and remain understandable to keyboard and screen-reader users.
An internal correctness objective might track stale-result incidents and leaked subscriptions in representative user flows. It is separate from API availability and any contractual SLA. The SOP should include a reproducible delayed-response fixture, ownership rules for subscriptions and the evidence needed before changing dependency handling. Do not turn off Strict Mode as the incident resolution.
Explore software development and observability and monitoring for application lifecycle and production diagnostics.
Technical reference
React useEffect reference, reviewed 19 October 2026.