DEV Community

SUPRATIM LALA
SUPRATIM LALA

Posted on

How declarative mode </> was lagging!

How does declarative mode work, and what does it offer?

  • First, we wrap BrowserRouter around our app, which connects your React app to the browser's address bar so you can change pages without reloading
    which gives us the true feel of a Single Page Application.

  • Next, we make routes and subroutes according to our choice.

<Routes>
  <Route index element={<Home />} />
  <Route path="about" element={<About />} />

  <Route element={<AuthLayout />}>
    <Route path="login" element={<Login />} />
    <Route path="register" element={<Register />} />
  </Route>

  <Route path="concerts">
    <Route index element={<ConcertsHome />} />
    <Route path=":city" element={<City />} />
    <Route path="trending" element={<Trending />} />
  </Route>
</Routes>
Enter fullscreen mode Exit fullscreen mode
  • If a path segment starts with : then it becomes a "dynamic segment". When the route matches the URL, the dynamic segment will be parsed from the URL and provided as params to other router APIs like useParams.
<Route path="teams/:teamId" element={<Team />} />
Enter fullscreen mode Exit fullscreen mode

Why was it not enough?

In Declarative Mode, the router acts strictly as a UI switcher
—it simply determines which component tree to render based on the current URL. The fundamental flaw is that data fetching was coupled to the React component lifecycle:

  • The Network Waterfall: React Router had to mount a parent component before its useEffect or React Query hook could fire. If a layout had nested child routes, the parent rendered, fetched its data, finished loading, rendered the child, and only then could the child begin fetching its own data.
  • Loading State Jitter & Layout Shifts: Every level of a nested route managed its own loading, error, and empty states. This caused cascading layout shifts (CLS) where users saw nested spinners popping in sequentially.
  • No Synchronization for Mutations: Submitting forms or mutating data meant manually managing pending states and manually triggering cache invalidation across every affected component to keep the UI in sync.
  • No Route Pre-fetching or Parallelization: The router couldn't know what data a page needed until the browser downloaded the JavaScript bundle, executed the code, and evaluated the component tree.

In the next part we will see how data mode fixed it ->

Top comments (1)

Collapse
 
kyisaiah47 profile image
Isaiah Kim

How does data mode handle a child loader that needs a value returned by its parent loader?