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