Headless CMS

Quick Tip: Sharing Data in Next.js with React Context

The React Context API is a data store that provides functionality for accessing data at the component level without passing it down through the application as props. I like to think of Context as “global” props or state that can be directly accessed from almost anywhere in the component tree.

Here at WebDevStudios, we recently used Context as a data store for WordPress menus in our Next.js WordPress Starter project. Context made accessing menu data from the Headless WordPress installation painless across the various navigational components.

In this article, we’ll take a quick look at the steps involved in setting up Context and how we used it to store menu data in the Next.js WordPress Starter.

How to Use React Context with Next.js

Implementing Context into Next.js applications can be broken down into the following tasks:

  1. Create Context
  2. Passing Data into Context
  3. Importing Context into Components

Create Context

To begin, we need to initiate a new Context . This involves creating the Context object and setting up the Context Provider.

The Context object will be used to store the menu data and the Provider component is responsible for delivering the Context to its children when requested.

// components/common/MenuProvider.js
import { createContext, useContext } from 'react'

// Create Context object.
const MenuContext = createContext()

// Export Provider.
export function MenuProvider(props) {
	const {value, children} = props
	
	return (
	   <MenuContext.Provider value={value}>
		{children}
	   </MenuContext.Provider>
	)
}

// Export useContext Hook.
export function useMenuContext() {
	return useContext(MenuContext);
}

Passing Data into Context

The next step is to pass data into the Context object. For this, we’ll use the Context Provider (MenuProvider) that was exported in the first step.

In our custom Next.js App component, we fetch the menu data from pageProps, convert it to state (navMenu) and then pass it as a value prop to the MenuProvider component.

// ./pages/_app.js
import {useState} from 'react'
import {MenuProvider} from '@/components/common/MenuProvider'

export default function App({Component, pageProps}) {
  // Get menu data via GraphQL query in `pageProps`.
  const {menu} = pageProps

  // Store menu as state for the MenuProvider.
  const [navMenu] = useState(menu)

  return (
    <MenuProvider value={navMenu}>
      <Component {...componentProps} />
    </MenuProvider>
  )
}

Note: The menu data above is being queried via GraphQL from a Headless WordPress installation in getStaticProps. An example of the returned object array is shown below.

// Example object array returned from GraphQL.
const menu = [
  {
    label: 'Homepage',
    href: '/'
  },
  {
    label: 'About',
    href: '/about'
  },
  {
    label: 'Blog',
    href: '/blog'
  },
  {
    label: 'Contact',
    href: '/contact'
  }
]

Importing Context into Components

Now that we’ve created the MenuContext object and hydrated the object with data, it’s time to import the MenuContext object directly into our Navigation component for rendering.

For this, we’ll import the useMenuContext function created in step one and map over the results to display the individual menu items.

// ./components/header/navigation.js
import {useMenuContext} from '@/components/common/MenuProvider'

export default function Navigation() {
  const menu = useMenuContext() // MenuContext object.
  return (
    <ul id="primary-menu">
      {!!menu &&
        menu.map((item, index) => {
          return (
            <li key={index}>
              <Link href={item.href}>
                <a>{item.label}</a>
              </Link>
            </li>
          )
        })}
    </ul>
  )
}

The big advantage in using Context in this situation is you no longer have to worry about passing data around via props; you can simply import the object directly into components as needed.

When Context May Not be the Right Choice

We love the Context API for how it simplifies sharing state between unrelated or distant components in a tree. However, that simplicity can also become a major pitfall of the API if not used moderately throughout an application.

The issue with Context is simple—when the state of a Context object is updated it triggers a re-render within all consumer components. This can expose significant performance issues in an application if many components are being re-rendered every time a state value is updated.

When using Context, it’s good to take into consideration how many components will be affected by a single state update and act accordingly on your findings.

Wrapping Up

The React Context API is an intuitive way to share data and state across an entire Next.js application. Props that are typically global, such as locale, user authentication and navigational menus are just a few examples of how Context can be used to make prop sharing easier than ever.

What are you using Context for in your Next.js applications?

Comments

Have a comment?

Your email address will not be published.

accessibilityadminaggregationanchorarrow-rightattach-iconbackupsblogbookmarksbuddypresscachingcalendarcaret-downcartunifiedcouponcrediblecredit-cardcustommigrationdesigndevecomfriendsgallerygoodgroupsgrowthhostingideasinternationalizationiphoneloyaltymailmaphealthmessagingArtboard 1migrationsmultiple-sourcesmultisitenewsnotificationsperformancephonepluginprofilesresearcharrowscalablescrapingsecuresecureseosharearrowarrowsourcestreamsupportunifiedupdatesvaultwebsitewordpress