Access React context outside of component

CaribouCode picture CaribouCode · Jan 14, 2019 · Viewed 8.1k times · Source

I'm using React context to store the locale for a NextJS website (e.g. example.com/en/). The setup looks like this:

components/Locale/index.jsx

import React from 'react';

const Context = React.createContext();
const { Consumer } = Context;

const Provider = ({ children, locale }) => (
  <Context.Provider value={{ locale }}>
    {children}
  </Context.Provider>
);

export default { Consumer, Provider };

pages/_app.jsx

import App, { Container } from 'next/app';
import React from 'react';

import Locale from '../components/Locale';


class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};
    const locale = ctx.asPath.split('/')[1];
    return { pageProps, locale };
  }

  render() {
    const {
      Component,
      locale,
      pageProps,
    } = this.props;

    return {
      <Container>
        <Locale.Provider locale={locale}>
          <Component {...pageProps} />
        </Locale.Provider>
      </Container>
    };
  }
}

So far so good. Now within one of my pages, I get data from Contentful CMS API in the getInitialProps lifecycle method. That looks a bit like this:

pages/index.jsx

import { getEntries } from '../lib/data/contentful';

const getInitialProps = async () => {
  const { items } = await getEntries({ content_type: 'xxxxxxxx' });
  return { page: items[0] };
};

At this stage I need to make this query with the locale so I need to access Local.Consumer in the above getInitialProps. Is this possible?

Answer

Gordon Burgett picture Gordon Burgett · Mar 1, 2019

This does not appear to be possible according to the documentation here: https://github.com/zeit/next.js/#fetching-data-and-component-lifecycle You access React context data by wrapping your component in the context's Consumer like this:

<Locale.Consumer>
  ({locale}) => <Index locale={locale} />
</Locale.Consumer>

But getInitialProps is run for top-level pages and does not have access to the props.

Can you get your entries in another React lifecycle method, like componentDidMount? Then you could store your items in the component state.