Andrea Ligios
Andrea Ligios

Reputation: 50203

Where to put Context Provider in Gatsby?

I need to run some functions (eg. Office UI Fabric React's initializeIcons()) and AXIOS call (eg. retrieve the logged-in user with Context API) only the first time the site is hit, then store the retrieved values in the React Context and make it available to the whole application.

Gatsby is wrapping my pages' content in a Layout, like:

const IndexPage = () =>
<Layout>
   Body of Index Page...
</Layout>
const AnotherPage = () =>    
<Layout>
   Body of Another Page...
</Layout>

with Layout being like:

const Layout = ({ children }) =>
<>
    <Header /> 
    <main>{children}</main>
    <Footer />
</>

I know where I can NOT put my Context:

I suppose I need a root <app> object to surround with my Context Provider, but what's a clean way to achieve that with Gatsby?

Where should I put my Context Provider?

Upvotes: 12

Views: 3763

Answers (2)

Andrea Ligios
Andrea Ligios

Reputation: 50203

For completeness, the APIs Gatsby provides (through gatsby-browser.js) to run a function only once are:

onClientEntry

export const onClientEntry = () => {
    console.log("Browser started!")
    // Put here run-only-once functions 
}

onInitialClientRender

export const onInitialClientRender = () => {
    console.log("First rendering completed!")
    // Put here run-only-once functions which need rendered output
}

Upvotes: 0

EliteRaceElephant
EliteRaceElephant

Reputation: 8162

You define a root layout. In contrast to the normal layout there are no "visible" page elements defined but hidden stuff you need on every page like ContextProviders, React Helmet, themes, etc:

RootLayout.jsx:

export default function RootLayout({ children }) {
  return (
    <>
      <Helmet />
        <ThemeProvider theme={theme}>
          <CssBaseline />
          <ContextProvider>
            {children}
          </ContextProvider>
        </ThemeProvider>
    </>
  );
}

Gatsby calls this root layout implicitly via gatsby-browser.js and gatsby-ssr.js and applies it to each of your pages. Those two identical lines of code are all you need for Gatsby to handle the rest for you.

gatsby-browser.js:

export const wrapRootElement = ({ element }) => <RootLayout>{element}</RootLayout>;

gatsby-ssr.js:

export const wrapRootElement = ({ element }) => <RootLayout>{element}</RootLayout>;

Summary:

  • You put your Context Provider in a root layout.

References:

  • I asked related questions here and here. The code I provided in this answer is the solution to your and my question. It is good coding practice adapted from frameworks such as React Redux to wrap your whole app with the Context Provider if your whole app needs this information.
  • The blog post @Lionel T mentioned.

Upvotes: 11

Related Questions