'Why does a context component re-evaluate during NextJs page routing?
Given a basic NextJs application with a simple context component and a couple of pages
// AppContextWrapper.js
export function AppContextWrapper(props) {
console.log('AppContextWrapper - component function executed');
const appContextState = useState();
return (
<AppContext.Provider value={appContextState}>
{props.children}
</AppContext.Provider>
);
}
// _app.js
function MyApp({ Component, pageProps }) {
return (
<AppContextWrapper>
<Layout>
<Component {...pageProps} />
</Layout>
</AppContextWrapper>
);
}
I notice that navigating from one page to another triggers re-execution of the AppContextWrapper component function.
In a basic non-NextJs React app this does not occur.
// index.js
ReactDOM.render(
<React.StrictMode>
<AppContextWrapper>
<App />
</AppContextWrapper>
</React.StrictMode>,
document.getElementById('root')
);
// app.js
function App() {
return (
<BrowserRouter>
<div>
<nav>
<ul>
<li>
<Link to='/'>Home</Link>
</li>
<li>
<Link to='/other'>Other</Link>
</li>
</ul>
</nav>
<Switch>
<Route path='/other'>
<OtherPage />
</Route>
<Route path='/'>
<HomePage />
</Route>
</Switch>
</div>
</BrowserRouter>
);
}
Presumably this occurs because in the NextJs app navigation causes reassignment of Component and pageProps in _app.js therefore causing re-execution of the MyApp component function.
I have several questions related to this.
Is re-execution of the context component function potentially a problem?
Is there somewhere in a NextJs application to install context components where this re-execution can be avoided?
Lastly, I've seen code that uses useMemo in a context function, like so...
// appContextWrapper.js
export function AppContextWrapper(props) {
console.log('AppContextWrapper component function executed');
const [appState, setAppState] = useState({});
const appContextState = useMemo(() => ({ appState, setAppState }), [appState, setAppState]);
return (
<AppContext.Provider value={appContextState}>{props.children}</AppContext.Provider>
);
}
I don't understand this approach, is it sound? My understanding is that useMemo should be used for memoizing props or computed values that don't change to prevent unnecessary re-execution of the component functions of child components. Using useMemo to hold values already managed by React via useState seems pointless and redundant.
Solution 1:[1]
I think the problem you are describing is from not using shallow routing.
Nextjs docs state this:
Shallow routing allows you to change the URL without running data fetching methods again, that includes getServerSideProps, getStaticProps, and getInitialProps.
You'll receive the updated pathname and the query via the router object (added by useRouter or withRouter), without losing state.
https://nextjs.org/docs/routing/shallow-routing
You can use shallow routing in Link by doing this:
<Link to='/other' shallow>Other</Link>
And in push likes this
push({pathname: "/other"},undefined,{shallow: true})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Daniel |
