7

We were using react's context API in our next.js 12 apps.

We want to upgrade to next.js 13.

We get this error:

react__WEBPACK_IMPORTED_MODULE_0__.createContext is not a function

For this code:

import React from 'react'

const SiteContext = React.createContext()

export default SiteContext

What should we do now? I can't find resources online for this.

Also, we need the Context API on the server because SEO matters and we don't want to render on the client.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
Big boy
  • 1,113
  • 2
  • 8
  • 23

3 Answers3

6

The issue is that you need the "use client" directive.

The error is being suppressed because of your import statement. Change the import to import { useContext } from 'react' and you will get the following error:

You're importing a component that needs createContext. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.

Checkout the beta docs for more details, but basically, ALL components inside the app directory are server components. For client components, you need to use the directive.

"use client"

import React from 'react'

const SiteContext = React.createContext()

export default SiteContext
jme11
  • 17,134
  • 2
  • 38
  • 48
  • 2
    Does this mean that we can't use Context API on the server side? Is it a React limitation, or a Next limitation? – Big boy Nov 01 '22 at 07:08
  • 2
    Yup, useState, useEffect and createContext are client-only features. The "use client" directive was introduced with React as part of the Server Components features, so it is a "React thing" but I'm not sure it's a limitation per se. If your component needs to support user interactions such as those that would require state, then it's a client component by definition. – jme11 Nov 01 '22 at 22:08
  • 1
    yes it's a client component. But can we render it on the server for the sake of SEO? Let's say we want to have a contact us form. It's a client component. But the `/contact` page needs to be rendered on the server so that Google can index it. – Big boy Nov 02 '22 at 02:05
  • 1
    Short answer is yes. Check out [docs](https://beta.nextjs.org/docs/rendering/fundamentals#client-and-server-rendering-at-the-component-level) for the details, but yes, both Server and Client Components can be prerendered on the server at build time. – jme11 Nov 02 '22 at 11:08
4

In app directory you create your context inside a client component. Because you will need useState,useEffect hooks. the way you crete context api is same as before. But you need to wrap top layout file with this context.

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head />
      <body>
        <main>
          <AuthContext>
            <main>
              {children}
            </main>
          </AuthContext>
        </main>
      </body>
    </html>
  );
}

AuthContext is a client component and wraps children. Normally client components cannot render server components but since we are using children prop, components inside children tree can be server components.

the problem with context api on the app directory is any component that needs to reach context has to be a client component because it needs to use useContext hook.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
  • Just to clarify, are you saying that placing any component inside of `AuthContext` does not automatically make it a client-side component? So if I place a component that does not useContext with `AuthContext`, it will still be rendered as a server component? – Lee Harrison Apr 25 '23 at 17:59
  • 1
    @LeeHarrison https://stackoverflow.com/questions/74992326/does-use-client-in-next-js-13-root-layout-make-whole-routes-client-component/75480826#75480826 – Yilmaz Apr 25 '23 at 21:16
3

Next 13 does not support the React Context API on the server is the issue. Considering SEO matters you would have to stick with the old apps/pages approach for now. I hope they support context soon.

r_flow
  • 31
  • 1