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. ReactWP asks the REST route endpoint for the normalized route payload
  3. the loader prepares the critical assets
  4. the page transition runs
  5. the new route is rendered without a full page reload

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.

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

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.