Next.js is one of the most popular and widely used React frameworks.
Using the Context API in Next.js is very simple but there are specific cases where you may need to wrap only certain pages by the provider.
To do this, create a new next project
npx create-next-app my-app
We are going to create a context that will increment and decrement a number.
Create a new folder components
and inside create a new file named context.js
then paste this code
import { createContext, useContext, useState, useCallback } from "react";
const Context = createContext({});
export const CountProvider = ({ children }) => {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((prevState) => prevState + 1);
}, [count]);
const decrement = useCallback(() => {
setCount((prevState) => prevState - 1);
}, [count]);
return (
<Context.Provider value={{ count, increment, decrement }}>
{children}
</Context.Provider>
);
};
export function useCount() {
return useContext(Context);
}
the custom hook useCount()
will allow us to use the values passed to the context provider.
In the _app.js file, add this new component
const Noop = ({ children }) => <>{children}</>;
Then in MyApp
component which is exported by default, we will add a prop named provider
which will be accessible in all pages and its value will be <Noop/>
if no context provider is passed as a value.
Now the _app.js file will be like this
import "../styles/globals.css";
const Noop = ({ children }) => <>{children}</>;
function MyApp({ Component, pageProps }) {
const ContextProvider = Component.provider || Noop;
return (
<ContextProvider>
<Component {...pageProps} />
</ContextProvider>
);
}
export default MyApp;
We will consume the provider in the home page like this
import styles from "../styles/Home.module.css";
import { CountProvider, useCount } from "../components/context";
export default function Home() {
const { increment, count, decrement } = useCount();
return (
<div className={styles.container}>
<button onClick={increment}>Increment</button>
<h1>{count}</h1>
<button onClick={decrement}>Decrement</button>
</div>
);
}
If you try it in the browser, you won't be able to increment or decrement a number because we don't have the provider as a prop in the page.
To make it work, add
Home.provider = CountProvider;
After reloading the page, you can increment and decrement the number.
Top comments (6)
Just wrap components that need state nothing more, not the whole app
In this article author describes approach of handling context by several pages, not components. It's important to note!
...
Thank you for this! I have a project where there are 2 separate messaging boards with their own contexts and a homepage that has links to both of them. I was having trouble persisting my session state when navigating from the homepage to my boards, because I had the session provider in the getLayout function of each board, which made it unmount on each navigation. This is much simpler and fixed my problem!
thank very much
Nice post, thank you!