DEV Community

Last Bencher
Last Bencher

Posted on

React interview practice: explain a stale search result before fixing it

A user searches for “react”, then quickly changes the search to “react hooks”. The second request finishes first. A moment later, results for the older search replace the current results.

The network did not necessarily fail. The UI accepted a response that no longer belonged to the current request.

This is a useful interview exercise because it tests reasoning about time, state and cleanup—not just whether you remember a Hook name.

Draw the sequence first

Time Event
1 Request A starts for “react”
2 Request B starts for “react hooks”
3 B finishes; the UI shows B
4 A finishes; an unguarded callback overwrites B

The requirement is not “use the last response to arrive.” It is “only the request belonging to the current search may update this result state.”

Clarify the intended loading experience as well. Should old results remain visible with a loading indicator, or disappear immediately? That is separate from preventing an obsolete response from winning.

Describe ownership, then implementation

Each search operation needs a way to determine whether it is still current when its asynchronous work finishes. In an Effect-based implementation, cleanup can mark an old operation inactive. React's Effect documentation describes aborting a fetch or ignoring its obsolete result during cleanup.

The following small JavaScript model demonstrates result ownership. It is not a complete React component or a production fetching library:

function createLatestResultGate() {
  let generation = 0;

  return {
    begin() {
      const mine = ++generation;
      return () => mine === generation;
    },
    invalidate() {
      generation += 1;
    },
  };
}

const gate = createLatestResultGate();
const isCurrentA = gate.begin();
const isCurrentB = gate.begin();

console.assert(isCurrentB(), "B owns the current result");
console.assert(!isCurrentA(), "A must not update the result");

gate.invalidate();
console.assert(!isCurrentB(), "Cleanup invalidates B too");
Enter fullscreen mode Exit fullscreen mode

This models the ordering rule without needing unpredictable network delays. A real integration must keep the gate scoped to the appropriate component/request lifecycle; recreating it for every callback would defeat the comparison. An Effect-local inactive flag is often simpler for one Effect.

Guard more than successful data

An obsolete request can also clear a loading indicator or display an error after a newer request succeeds. Apply the ownership rule to every asynchronous state transition associated with the request, including error handling and finalization.

For example, if A fails after B succeeds, the user should not suddenly see A's error presented as the status of B. That case belongs in the test plan alongside out-of-order successes.

Debouncing answers a different question

Delaying a request until typing pauses may reduce how many operations start. It does not establish which already-started request owns the current state.

In an interview, separate the two requirements explicitly: controlling request frequency and preventing stale updates. Choosing one does not demonstrate that the other is solved.

Test sequences, not just the happy path

Use controllable promises or a request mock so the test decides completion order:

  • A starts, B starts, B succeeds, then A succeeds: B must remain visible.
  • A starts, B starts, B succeeds, then A fails: A's error must not replace B's status.
  • A starts, then the component unmounts: the old operation must not update its state.
  • The latest request fails: the current error must still be shown.

Also explain what happens to loading state in each sequence. Merely hiding every error would make one test pass while breaking the actual feature.

Avoid rebuilding your entire data layer in the interview

If the application already uses a framework loader or client-side query cache, explain how its request identity, cancellation and cache behavior apply. React discusses the limitations of manual fetching in Effects in its useEffect reference. A small example proves understanding; it does not justify replacing the application's existing data layer.

Disclosure: I am Raviindra Wadile, creator of wasAsked. I use interview questions as prompts for explaining behavior and testing assumptions. The site offers public question browsing and a browser-local practice shortlist; this article is an educational exercise, not a report of a production incident.

Top comments (0)