Next.js Discord

Discord Forum

PPR vs Parallel Routes: Can they do the same thing?

Answered
Thrianta posted this in #help-forum
Open in Discord
ThriantaOP
Can I render a dynamic navbar as a @navbar "page"/slot, and have a SSG blog page/slot, and end up with something similar to PPR? As in, the blog post page/slot will be cached, and the navbar page/slot will be rendered dynamically and streamed in?
Answered by Thrianta
Unfortunately, after a trivial test, it doesn't work like that.

// src/app/@nav/page.tsx

import { cookies } from "next/headers";

export default function Navbar() {

  return (
    <div className="bg-slate-100 text-black p-5 flex flex-row justify-between">
      <span>my nav bar</span>
      <span>{cookies().get("user")?.value ?? "no-user"}</span>
    </div>
  )
}


// src/app/page.tsx

export default function Home() {
  return (
    <div>
      <h1>Home</h1>
      
    </div>
  );
}


// src/app/layout.tsx

export default function RootLayout({
  children,
  nav
}: Readonly<{
  children: React.ReactNode;
  nav: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>{nav}{children}</body>
    </html>
  );
}


With build output of:
bash 

Route (app)                              Size     First Load JS
┌ ƒ /                                    142 B          87.1 kB
└ ○ /_not-found                          872 B          87.8 kB
+ First Load JS shared by all            87 kB
  ├ chunks/660-ce879c34dbe3fefb.js       31.5 kB
  ├ chunks/e6e143be-b81e610fa28b7c47.js  53.6 kB
  └ other shared chunks (total)          1.86 kB


○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand
View full answer

15 Replies

This one question gives me a lot of headach, I hope PPR stable will soon be released so we can experiment more in practice and see how it works...
I'll try to sum it up though:
- PPR is a dynamic component in a static shell. Currently, if you want to keep a page static, but have request specific stuff to show in the interface, what you will do is crafting a client component. Client-side, you can send request to an API endpoint to get user specific data and display them. Ther rest of the page stays server-side, statically rendered. It sucks to have to use a client component. PPR is the same thing, but you can use dynamically server-side rendered component instead of a client component. Use case: a component showing the connected user's name, on a blog that is otherwise static
- parallel route is the most complicated pattern I've ever seen and is difficult to figure, but basically it's a kind of dynamic loading for RSCs. Say parallel routes do not exist, and you have 2 things to render : the main content of a blog post, and an administration area that allows admin to edit the content. You want the admin area only for admins of course.
what will you do ?
you will craft 2 components, import them, and render <Admin condtionnaly
like function BlogPage() { const isAdmin = checkAdminFromCookies(); return (<div><BlogPost />{isAdmin && <AdminArea /></div>)
I think the problem is that it means you are loading all the JS for AdminArea even if you don't render
with a parallel route, instead you let Next.js treat "AdminArea" as a route of its own, so it will split the code accordingly
if you don't render it, nothing happens
=> this needs verification though because I haven't used them much and didn't have time to run experiments around parallel routes
I don't know what happens eg if the page is static and one // route is dynamic
and not sure about how much PPR and // routes interact together, they don't exactly solve the same set of issues
ThriantaOP
Thanks for your help, Eric. 🙂

I hope I can find the time to run a few experiments to test out // routes in depth. I also can't wait for PPR to become stable; I wish there was [areweturboyet](http://areweturboyet.com) for it!

Im going to leave this unanswered for now. Hopefully someone else contributes something juicy.
ThriantaOP
Unfortunately, after a trivial test, it doesn't work like that.

// src/app/@nav/page.tsx

import { cookies } from "next/headers";

export default function Navbar() {

  return (
    <div className="bg-slate-100 text-black p-5 flex flex-row justify-between">
      <span>my nav bar</span>
      <span>{cookies().get("user")?.value ?? "no-user"}</span>
    </div>
  )
}


// src/app/page.tsx

export default function Home() {
  return (
    <div>
      <h1>Home</h1>
      
    </div>
  );
}


// src/app/layout.tsx

export default function RootLayout({
  children,
  nav
}: Readonly<{
  children: React.ReactNode;
  nav: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>{nav}{children}</body>
    </html>
  );
}


With build output of:
bash 

Route (app)                              Size     First Load JS
┌ ƒ /                                    142 B          87.1 kB
└ ○ /_not-found                          872 B          87.8 kB
+ First Load JS shared by all            87 kB
  ├ chunks/660-ce879c34dbe3fefb.js       31.5 kB
  ├ chunks/e6e143be-b81e610fa28b7c47.js  53.6 kB
  └ other shared chunks (total)          1.86 kB


○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand
Answer