DEV Community

Cover image for Next.js, integrate React Context only in certain pages
Enoch Ndika
Enoch Ndika

Posted on

Next.js, integrate React Context only in certain pages

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
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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}</>;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

After reloading the page, you can increment and decrement the number.

Source code

Top comments (6)

Collapse
 
ivan_jrmc profile image
Ivan Jeremic

Just wrap components that need state nothing more, not the whole app

Collapse
 
nosovandrew profile image
Andrew Nosov

In this article author describes approach of handling context by several pages, not components. It's important to note!

Collapse
 
aflood32 profile image
a-flood-32

...

Collapse
 
jakubsekula profile image
jakub-sekula

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!

Collapse
 
heywirdgirl profile image
van Manh

thank very much

Collapse
 
hidekih profile image
Alexandre Hideki Siroma

Nice post, thank you!