5

I'm working on a next.js app and my page layout is going through the following hierarchy:

  _app.js
     Page.js
         Header.js
         PageContent.js

I need to pass some parameters from PageContent to Header without using redux.

Inside _app.js I have the following:

class Main extends App {
  render() {
  const {
    Component,
    pageProps,
    apollo,
    router: { route }
  } = this.props;

 return (
  <ApolloProvider client={apollo}>
      <Page
        pathname={route.split("/")[1]}
        {...pageProps}
        localLinks={Component.LocalLinks}
        render={props => <Component {...props} />}
      />
   </ApolloProvider>
  );
 }
}

I'm assuming there should be a way to pass some propse (pageProps) from PageContent to _app and pass that down to Page and make them accessible to header. Is there a next.js specific trick here that I'm not familiar with?

Adam Boostani
  • 5,999
  • 9
  • 38
  • 44
  • I am not familiar with next.js, but in React you can just lift the state up, so your children will have access to modify those props that could be shared between sibling components: https://reactjs.org/docs/lifting-state-up.html – Bruno Monteiro Jan 10 '20 at 02:04

2 Answers2

1

Here's a full example with contexts (approach previously suggested in this other answer by slightly modifying https://github.com/vercel/next.js/tree/7df7c5e80515eea6745fd59e54d87e5ee709fe0c/examples/with-app-layout tested on Next.js 12.0.7 and React 17:

pages/_app.js

import React from 'react'

export const MyAppContext = React.createContext({
  n: 0,
  setN: undefined,
});

function Header(props) {
  return <div>n = { props.n }</div>
}

export default function App({ Component, pageProps }) {
  const [n, setN] = React.useState(0)
  return (
    <MyAppContext.Provider value={{n, setN}}>
      <Header n={n} />
      <Component {...pageProps} />
    </MyAppContext.Provider>
  )
}

pages/index.js

import { MyAppContext } from './_app.js'
import React from 'react'

export default function Home() {
  const {n, setN} = React.useContext(MyAppContext)
  React.useEffect(() => {
    setN(new Date().getTime())
  }, [])
  return <div>test</div>
}

package.json

{
  "name": "with-app-layout",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "12.0.7",
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "license": "MIT"
}

and run with:

npm install
npm run dev

The useEffect is required otherwise you will get the error:

Cannot update a component (`App`) while rendering a different component (`Home`)

which is mentioned at: Cannot update a component while rendering a different component warning Basically you cannot call .set methods directly from render.

If it's something that depends only on the page and not props

The following works without contexts, I wonder if setting such attributes could cause any problems down the line:

pages/_app.js

function Header(props) {
  return <div>n = { props.n }</div>
}

export default function App({ Component, pageProps }) {
  return (
    <>
      <Header n={Component.n} />
      <Component {...pageProps} />
    </>
  )
}

pages/index.js

export default function Home() {
  return <div>test</div>
}
Home.n = 1
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
0

You can use context api or Parent container state (here Page component).

First Way -> Use context api

Second Way

  • make State on page component
  • pass StatemodifierFunction props to pageContent
  • then modify state by calling this StatemodifierFunction
  • then pass this state to Header Component

** Third way **

  • you can use react node also
Man
  • 742
  • 1
  • 6
  • 23