Skip to main content

Routing and Navigation

Role​

ReactWP uses React Router for browser history, but WordPress still owns the route payload.

That means navigation is split into two layers:

  • React Router keeps the browser URL and history in sync
  • ReactWP fetches, caches, and renders the actual route payload from WordPress

Main Files​

  • src/themes/reactwp/js/inc/RouteService.js
  • src/themes/reactwp/js/inc/useRouteTransition.js
  • src/themes/reactwp/js/components/AppLink.jsx
  • src/mu-plugins/plugins/reactwp/template/inc/routes/rest.php

Direct Load vs Client Navigation​

On a direct page load:

  1. WordPress resolves the current object
  2. RouteResolver turns it into a route payload
  3. Bootstrap injects that route into the initial JSON payload
  4. React mounts from that payload

On client-side navigation:

  1. React Router detects the requested location
  2. the leave animation starts immediately, in parallel with the REST route request
  3. the loader prepares the next template and critical assets as soon as the payload is available
  4. ReactWP waits for both leave and critical preparation before proceeding with the route swap
  5. the new route renders without a full page reload, then enters after committed critical display and scroll placement

The network wait happens alongside or after the outgoing animation. It no longer delays the start of that animation. See Page Transitions for the completion and failure behavior.

Route Fetching​

The REST endpoint lives at:

  • reactwp/v1/route

The frontend usually reaches it through:

  • runtime.system.routeEndpoint

RouteService.js normalizes the returned payload so the runtime always gets a predictable route shape.

Route Cache​

RouteService.js keeps an in-memory Map keyed by normalized pathname plus normalized search string.

That means:

  • revisiting a page in the same session can reuse the existing payload
  • a hover-prefetched route can be available faster on click
  • back and forward navigation can also benefit from the same cached payload

Hashes are not part of route identity. ReactWP treats:

  • pathname + search as the route key
  • hash as local scroll state

Important Cache Limitation​

The route cache is session memory, not a live invalidation system.

If the content of a page changes in WordPress while the app is already open, a previously cached route can stay stale until:

  • the page is fully reloaded
  • the tab is reopened
  • the cache is cleared by a future runtime change

ReactWP does not currently ship automatic route cache invalidation.

The ReactWP cache generation rotates Cache Storage and initial asset URLs, but an already-running tab still keeps its route memory until a full page load. Changing the server generation cannot mutate JavaScript memory in a remote open tab.

Prefetching​

AppLink.jsx prefetches routes on:

  • mouse enter
  • focus

It does that by calling Loader.prepareRoute(...), which means the route payload and its critical asset preparation can already be in flight before the click happens.

Internal Navigation Outside #app​

ReactWP also listens for clicks on internal anchors outside #app.

This matters for elements such as:

  • portal-mounted header content
  • other shell-level anchors rendered outside the main React tree

That behavior lives in useInternalNavigation.js.

If an anchor outside #app points to an internal URL, ReactWP can intercept it and turn it into a client-side navigation.

Forcing A Full Browser Navigation​

If you want a shell-level anchor outside #app to bypass React navigation, set:

data-router="false"

on that raw anchor element.

This tells the internal navigation listener to leave the click alone so the browser can perform a normal page load.

History Arrows​

Back and forward navigation use the same ReactWP route transition flow as normal internal links.

That is why the route transition layer and the route cache both matter for:

  • normal clicks
  • browser back
  • browser forward

Query Strings and Hashes​

ReactWP normalizes query strings through URLSearchParams. Repeated query keys become arrays in route.query.

A location such as /projects/?type=house#results is treated as:

  • route identity: /projects/?type=house
  • local scroll target: #results

Hash-only links on the current route bypass the leave/enter transition. ReactWP refreshes the scroller and scrolls to the target after the browser frame is ready.

By default, a same-page AppLink or internal Button also writes the target hash to the URL and adds a browser history entry. Pass updateHash={false} when the click should scroll to the target without changing the visible URL. This option does not remove the link's href; it only changes how a normal click updates history. See Components for examples.

Use these components when you want standard ReactWP navigation behavior:

  • AppLink for internal links
  • Button with to or internal href for navigation actions

Use a raw anchor only when you intentionally want browser-native navigation behavior.