Home / Articles

Build a React Search Interface with Clear State Ownership

Build a React search interface where events, derived values, request lifetimes and evidence display stay separate, so answers match the query that asked.

3 min read709 words

This article is published in English.

A search backend can retrieve the right documents and still produce a confusing experience. A slow response for an earlier query may overwrite a newer result. A filter count may lag behind the list. A source panel may show citations from the previous answer.

These failures often begin with unclear ownership: several pieces of state represent the same fact, or effects infer an event that the interface already handled.

For a React knowledge application, start by deciding what each value means and which operation is allowed to change it.

Separate the input from the submitted question

The text currently in the search box and the question associated with a displayed answer are different things. A user may edit the input while reading the previous result.

Model that difference explicitly. Keep the draft input, the submitted query or request identity, and the resulting request state. The result should retain the query it answers.

For submit-driven search, the submit handler already knows that a search was requested. It can call the operation directly. Setting a boolean solely so an effect can notice it adds another transition without clarifying the workflow.

Live search has a different requirement: results track an evolving query. A query layer or an effect with a deliberate lifetime can own that synchronization. Choose the behavior first, then the implementation boundary.

Derive values that do not need independent storage

If a result count comes from the visible array, calculate it from that array. Storing both the array and a separately updated count creates two values that can disagree.

The same applies to labels assembled from current state and simple client-side filtering. An effect that copies one React value into another is often a sign that the second value should be derived instead.

This does not mean all local state is redundant. An editable draft can intentionally differ from server data. The important part is defining when a new server value may replace the user's work.

Give asynchronous work a clear owner

Consider two submitted questions. Request A starts first, request B starts second, and B finishes first. If A later replaces the result unconditionally, the screen displays an answer to the wrong question.

Associate results with request identities. Only the active request may replace the active result. Cancel obsolete work when the transport supports cancellation, and still handle the possibility that earlier work completes.

A query layer can provide these behaviors, or a dedicated request controller can implement them. The component should consume an explicit state such as idle, loading, success, or error, instead of coordinating a chain of effects whose dependencies happen to trigger the next step.

Subscriptions, timers, and browser listeners still need lifecycle cleanup. Treat an effect as ownership of an external synchronization process, with setup and cleanup that make sense together.

Keep evidence attached to its answer

Return the answer and its source references as one response associated with the submitted query. When the active result changes, update them together.

A useful source reference includes a stable source identifier and a passage location. The source-quality workflow explains why a title alone is insufficient. If the application supports evidence previews, preserve the relationship between each displayed claim and the passage offered to justify it.

Distinguish an empty result from an unanswered question and a failed request. They imply different next steps for the reader, even if all three would otherwise render an empty list.

Test the interaction under inconvenient timing

Submit two questions quickly and make the first request slower. Change filters while a request is active. Navigate away before completion. Retry after an error. Check whether the answer, query label, and source panel remain consistent.

These cases extend RAG evaluation into the interface. Evidence quality matters only if the user sees the evidence associated with the answer they actually requested.