React Forum
Blog & Guide Responses
Jun 11, 2022 · 04:00 AM

MDN URLSearchParams - discussion (2022-06-11)

Started by Lena Fischer
externalmdnurlsearch paramsroutingfilters

For filter/search-heavy UIs: how do you handle query params without ending up with a bunch of sync effects and edge cases around back/forward?

Read the docs

Do you treat search params as route truth (and derive the rest), or treat them as a serialization format? How do you model multi-select params (repeated keys vs comma-separated) so it's stable and testable? And what signals do you render so bugs are understandable from a screenshot?

Comments (10)

Back to latest
Noah Vance
Jun 11, 2022 · 04:06 AM

If you have an effect that says "when params change, set state", you're already in trouble.

Make params the truth or make state the truth, but don't try to keep them in sync after render.

Dmitri Kline
Jun 11, 2022 · 04:14 AM

We treat params as serialized truth and store a normalized shape in the route doc as derived keys.

Raw params are wide/ugly. The doc holds a stable surface like { q, tags, sort } and everything renders from that.

This maps cleanly to Routing and Navigation and the docs posture in Core Concepts Best Practices.

Salma Qureshi
Jun 11, 2022 · 04:22 AM

Normalization snippet that avoids "mystery array vs string" bugs:

ts
type Filters = { q: string; tags: string[]; sort: 'new' | 'top' };

function parseFilters(sp: URLSearchParams): Filters {
  const q = sp.get('q') ?? '';
  const tags = sp.getAll('tag');
  const sort = sp.get('sort') === 'top' ? 'top' : 'new';
  return { q, tags, sort };
}
Keira Santos
Jun 11, 2022 · 04:31 AM

Counterpoint: repeated keys make URLs annoying for some products (they insist on commas).

If you do commas, you need a single normalization helper and you can't let components split/join ad hoc.

Lena Fischer
Jun 11, 2022 · 04:35 AM

Yep, product is already hinting at commas. I'm trying to keep it from becoming "everyone parses it differently".

Keira Santos
Jun 11, 2022 · 04:38 AM

Then I'd treat parsing as a route boundary and store the normalized tags array as the contract.

Theo Bennett
Jun 11, 2022 · 04:44 AM

Signals are huge here. We render a tiny filterSignal={q,tagsCount,sort} in the shell.

It stops bug reports like "it filtered wrong" from being vague. You can see what the app thought the filters were.

We basically copied the render-visible contract signal idea from Testing and Debugging and it made reproductions so much easier.

Hana Saito
Jun 11, 2022 · 04:52 AM

Also: prefer explicit reset actions over effects that try to fix state when params disappear. Timing bugs are brutal here.

Maya Henson
Jun 11, 2022 · 05:03 AM

We made default params part of the contract: if sort isn't present, it's new and we render that as evidence.

Otherwise components treat "missing" differently and UI drifts between panels.

Amina Farouk
Jun 11, 2022 · 05:15 AM

The failure mode for us was encoding too much derived stuff into params (like precomputed ids).

We only keep inputs in params. Everything derived is stored as evidence in the doc so it stays deterministic and testable.

Jules Kwon
Jun 11, 2022 · 05:27 AM

If you can paste the URL into chat and someone can predict the UI from it, you did it right.

Benji Rios
Jun 11, 2022 · 05:41 AM

Query params are fine. The bug is letting parsing be distributed across components. Centralize parsing, store normalized contract, render signals.