9

How do you pass props to the the page.jsx of layout? (NEXT 13)

//app/blog/layout.jsx

export default function RootLayout({ children }) {
  return (
    <div>
      <Navbar />
      <Sidebar />
      {/*How do I pass any props from this root layout to this {children} that Im getting from page.jsx*/}
      {children}
    </div>
  );
}

Basically, How do you pass a prop to a function prop (Next. JS 13)?

Vivaan Kumar
  • 457
  • 3
  • 4
  • 9

4 Answers4

10

According to the next13 docs you cannot:

It's not possible to pass data between a parent layout and its children. However, you can fetch the same data in a route more than once, and React will automatically dedupe the requests without affecting performance.

Because the layout component refers to a component that defines the overall structure and arrangement of other components within an application or a specific section of the UI. it is not designed to implement state management. its whole purpose is to reduce the time to first render to increase the user experience

But I found a way. In Rootlayout, console.log(props)

export default function RootLayout(props) {
  console.log("props in layout",props)
  return (
        <div>
          {props.children}
        </div>
  );}

this is what you will see

props in layout {
  children: {
    '$$typeof': Symbol(react.element),
    type: {
      '$$typeof': Symbol(react.module.reference),
      filepath: '/home/tesla//node_modules/next/dist/client/components/layout-router.js',
      name: '',
      async: false
    },
    key: null,
    ref: null,
    props: {
      parallelRouterKey: 'children',
      segmentPath: [Array],
      error: undefined,
      errorStyles: undefined,
      loading: undefined,
      loadingStyles: undefined,
      hasLoading: false,
      template: [Object],
      templateStyles: undefined,
      notFound: [Object],
      notFoundStyles: undefined,
      childProp: [Object],
      rootLayoutIncluded: true
    },
    _owner: null,
    _store: {}
  },
  // THIS IS HOW WE PASS PROPS
  params: {}
}

Many properties are not extensible but params. we can dynamically add properties to this object. for example

     props.params.newProp = "testing";

Now visit page.js and

const Page = (props) => {
  console.log("props in page", props);
  return ()}

you will see that props is added to the params object

enter image description here

No matter what I tried, page.tsx had only two props: params and searchParams. searchParams is automatically populated if you have query parameters on url. So, I think params are the only way to pass props from the root layout. you can pass functions too

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
  • 1
    Actually, `params` is the dynamic route params object of the page. So, in a dynamic segment defined as `[slug]`, `page.tsx`'s `params` prop will contain the following shape: `params: { slug: 'some-slug' }`. – ivanatias Nov 27 '22 at 02:30
  • @ivanatias correct. I meant to say params are only way to pass props. I am not sure if this is the way to handle it butnext.js has no docs yet and there is alot of issues as of now – Yilmaz Nov 27 '22 at 02:36
  • 2
    Oh, I see. As per [Next.js docs](https://beta.nextjs.org/docs/routing/pages-and-layouts#layouts), it's not possible to pass data between a parent layout and its children. But what you mention in the answer is one interesting finding, didn't know you could extend `params` object and make the props available for layout's children. – ivanatias Nov 27 '22 at 03:14
  • Was looking for the same, but other way around, page to layout. Old _app and Component props could do this. Can't find a way to do it in v13. I guess they tried really hard to make layouts not re-render and preserve state so they removed this functionality. Then they added new fetch and much better caching so idea si that both layout and page fetch the same data which will never be fetched two times during render cycle but cached... – Mirko Vukušić Jan 21 '23 at 13:14
  • ... Not sure about the boilerplate, but fetch caching might be a good solution. However, what about sharing props that are not in DB and external source and cannot be fetched? Like.... each page changing one css class in header layout (i.e. color of the navigation). Then we have to use context? And what if I want server side component and cannot use context? Tried everything but I think I'll be forced to go back to express/handlebars for my server side rendering of most pages. – Mirko Vukušić Jan 21 '23 at 13:15
  • You're supposed to use Context for this, which will work if the variable never changes. Otherwise I'm stuck on this in next app router too. – pguardiario May 16 '23 at 02:41
  • This indeed only works when set in the root layout. Sadly, no luck when manipulating the parameters in a client component. – Linus H. Jun 12 '23 at 12:58
2

To pass props from your Layout component(RootLayout for you case) to page.jsx.

//app/blog/layout.jsx

export interface items {
  foo: string;
  bar: string;
}

export default function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: {
    foo: string;
    items: items;
    age: number;

  };
}) {

  params.foo = "bar"; //string example

  params.items = { foo: "bar", bar: "foo" }; //object example

  params.age= 1; //number example

  return (
    <html lang="en" className="">
      <body>{children}</body>
    </html>
  );
}

//app/blog/page.jsx

export default function Dashboard({
  params,
}: {
  params: { foo: string; items: items; age: number };
}) {
  console.log(params.foo); //bar
  console.log(params.items); //{foo: 'bar', bar: 'foo'}
  console.log(params.age); //1
  return (
    <div></div>
  );
}
asavor
  • 101
  • 1
  • 6
0

You can just utilize React Context:

// layout.tsx

import React from 'react';

export const PageContext = React.createContext(null);

export default function SomeLayout({children}) {
   const [search, setSearch] = React.useState('foo');
   return <PageContext.Provider value={search}>{children}</PageContext.Provider>
}
// page.tsx

import React from 'react';
import PageContext from '../layout.tsx';

export default function SomePage() {
   const search = React.useContext(PageContext);
   console.log(search);
   return null;
}
Vasp
  • 15
  • 4
-2

In case if you want to send this props of children to Navbar component

<Navbar children = {children} />
Mayank Gupta
  • 153
  • 5