React Forum
Blog & Guide Responses
Oct 29, 2022 · 04:00 AM

MDN History API - discussion (2022-10-29)

Started by Camille Duarte
externalmdnhistorynavigationback/forwardrouting

We’re trying to make our back/forward story deterministic, and it’s forcing us to be honest about what state is URL truth vs what state is route doc truth.

Read the docs

Do you ever use pushState/replaceState directly in app code, or do you keep it strictly behind routing primitives? How do you keep navigation changes explainable (so support can tell what happened from a screenshot + URL)? What’s your rule for URL params vs route state when deep links need to reproduce UI posture?

Comments (10)

Back to latest
Maya Henson
Oct 29, 2022 · 04:06 AM

If you’re calling History API directly, you’re basically writing a router. I only do it when there’s a clear integration boundary.

Dmitri Kline
Oct 29, 2022 · 04:14 AM

We avoid direct calls and instead treat navigation as a contract surface (route state + rendered posture).

The History API is the transport; the route doc is the meaning after render.

Related: Routing and Navigation and Navigation Routines (Deep Dive #4).

Salma Qureshi
Oct 29, 2022 · 04:22 AM

When we *did* need History API for an embed integration, we wrapped it and rendered a marker so it stayed narratable:

ts
export function replaceUrl(url: string, reason: string) {
  history.replaceState({ reason }, '', url);
}
tsx
replaceUrl(`/search?q=${q}`, 'filters');
return <div data-nav="replace" data-reason="filters" />;
Keira Santos
Oct 29, 2022 · 04:31 AM

Counterpoint: sometimes direct replaceState is the least bad option for “update the URL without changing the route”.

But you still need strict rules, or you’ll drift into URL-sync effects that fight back/forward.

Camille Duarte
Oct 29, 2022 · 04:36 AM

Yeah, that’s exactly the case for us (filter UX wants URL updates without a full navigation).

We’re trying to keep the rule “write on intent, never in an effect” and see if it holds.

Keira Santos
Oct 29, 2022 · 04:39 AM

That rule is solid. The moment you sync in an effect, you’re done.

Noah Vance
Oct 29, 2022 · 04:47 AM

We also learned that “URL as hint” doesn’t mean “URL is irrelevant”.

Deep links still need a stable entry point, then route state can take over post-render.

Theo Bennett
Oct 29, 2022 · 04:56 AM

If you want deterministic back/forward, you have to pick a contract: URL truth or route doc truth.

A hybrid can work, but only if the route renders the resolved truth so you can tell which one won.

Amina Farouk
Oct 29, 2022 · 05:07 AM

We got rid of a bunch of “back takes you to a weird state” bugs by storing derived evidence once and reading from the doc everywhere.

When each component re-derives from URL, you get disagreement.

Priya Liao
Oct 29, 2022 · 05:21 AM

MDN has a good explanation of history entries, but the important app-level lesson is: history is a list of contracts.

If the contract isn’t visible, the list becomes scary.

Inez Park
Oct 29, 2022 · 05:32 AM

We render a data-route marker for support. It’s not fancy, but it turns “I clicked back and it broke” into “I clicked back to route X with posture Y”.

Benji Rios
Oct 29, 2022 · 05:44 AM

If you’re touching the History API directly, put a reason string on every call and render the reason somewhere.

It’s the only way it stays reviewable over time.