DEV3 Technologies home

DEV3 Developer Forum

Why do I get 'createContext only works in Client Components' in Next.js?

Next.js helpSolved0 views
dev3 ·

I created a ThemeContext with createContext in a file used by app/layout.tsx and Next says: 'You're importing a component that needs createContext. It only works in a Client Component'. How should I structure providers?

#nextjs#react#context

0

1 reply

dev3 · Accepted answer

Context needs React state at runtime, which server components do not have. Put the provider in its own client component and render it inside the (server) layout.

// app/providers.tsx
"use client";
import { createContext, useContext, useState } from "react";

const ThemeCtx = createContext<{ dark: boolean; toggle: () => void } | null>(null);

export function Providers({ children }: { children: React.ReactNode }) {
  const [dark, setDark] = useState(false);
  return (
    <ThemeCtx.Provider value={{ dark, toggle: () => setDark((d) => !d) }}>
      {children}
    </ThemeCtx.Provider>
  );
}

export function useTheme() {
  const ctx = useContext(ThemeCtx);
  if (!ctx) throw new Error("useTheme must be used inside <Providers>");
  return ctx;
}
// app/layout.tsx (server component)
import { Providers } from "./providers";

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

Why this works

children passed into a client component can still be server components, because they are rendered on the server first and passed through as already-rendered output. So wrapping the whole app in a provider does not turn the pages into client code.

Tips

  • Keep providers as deep as practical and combine several in one Providers component.
  • Libraries that use context (React Query, theme libraries, MUI) need the same wrapper.
  • Do not share request-specific data via a module-level variable on the server: different users share the module. Use props, cache() or headers.

Pitfall: any file that imports a hook such as useState or useContext must be a client component, including small helpers, or you hit the same error in a different file.

0

Your reply

Every post is reviewed by DEV3 before it appears. Usually reviewed within 24 hours.

Markdown supported. Use ``` for code blocks. Images are not allowed.