Skip to solution
hardFrontend

What changed with Context in React 19 (`<Context>` as a provider)?

62 views
01

Understand the problem

Question presented to candidate: "React 19 changed the Context syntax. What changed, and does existing code still work?"

What a strong answer should cover:

  • You can now render the context object itself as the provider: <ThemeContext value={x}> instead of <ThemeContext.Provider value={x}>.
  • Context.Provider still works — this is additive, not a breaking change, and existing code needs no migration.
  • The implementation detail worth knowing: Context.Provider === Context is now true, which is why both syntaxes render identically.
  • Context.Consumer is deprecated in favour of useContext, though it still exists. The render-prop consumer predates hooks.
  • Nothing about the behaviour changed: consumers still all re-render on a value change, the default value still applies only when there is no provider, and there is still no selector mechanism.
  • Related React 19 context change: use(Context) can read a context conditionally, because use allocates no hook slot — unlike useContext, which obeys the Rules of Hooks.
  • Migration: cosmetic. A codemod exists; there is no urgency.

Clarifying questions expected:

  • "Are we on React 19 across the whole codebase, or is this a shared library that must support 18?"

Code / implementation expected: Yes — both syntaxes side by side, plus the conditional use(Context) read.

reactreact-19context
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for React interviews — assumes the Context API. Difficulty: Hard

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. Every claim below — including whether the old syntax still works and what Con

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

Both provider syntaxes, and a conditional read with use()
Run Playground
import { createContext, useContext, use, useState } from "react";

const ThemeContext = createContext("default (no provider)");

// The React 19 implementation detail that makes both spellings work.
const providerIsContext = ThemeContext.Provider === ThemeContext;

function ReaderWithUseContext() {
  // useContext obeys the Rules of Hooks: unconditional, top level.
  const theme = useContext(ThemeContext);
  return <Line label="useContext" value={theme} />;
}

function ReaderWithUse({ skip }) {
  // use() may be called CONDITIONALLY — it allocates no hook slot, so there is
  // no call-order mapping to corrupt. useContext here would be illegal.
  if (skip) return <Line label="use() — skipped" value="did not read" />;
  const theme = use(ThemeContext);
  return <Line label="use() — read" value={theme} />;
}

function Line({ label, value }) {
  return (
    <p style={{ margin: "4px 0", fontSize: 14 }}>
      <code style={{ display: "inline-block", minWidth: 150 }}>{label}</code>
      {value}
    </p>
  );
}

function Panel({ title, children }) {
  return (
    <section style={{ border: "1px solid #ddd", borderRadius: 8, padding: 12, marginBottom: 10 }}>
      <h4 style={{ margin: "0 0 6px" }}>{title}</h4>
      {children}
    </section>
  );
}

export default function App() {
  const [skip, setSkip] = useState(false);

  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6, maxWidth: 470 }}>
      <p style={{ background: "#eef6ff", padding: 10, borderRadius: 6, fontSize: 14 }}>
        <code>ThemeContext.Provider === ThemeContext</code> is{" "}
        <strong>{String(providerIsContext)}</strong> — which is why both spellings
        below render identically.
      </p>

      {/* React 19: the context itself is the provider */}
      <ThemeContext value="dark (new syntax)">
        <Panel title="New: <ThemeContext value=...>">
          <ReaderWithUseContext />
        </Panel>
      </ThemeContext>

      {/* Still fully supported, no warning */}
      <ThemeContext.Provider value="light (old syntax)">
        <Panel title="Old: <ThemeContext.Provider value=...>">
          <ReaderWithUseContext />
        </Panel>
      </ThemeContext.Provider>

      {/* No provider at all — the default applies */}
      <Panel title="No provider — the createContext default">
        <ReaderWithUseContext />
      </Panel>

      <ThemeContext value="read conditionally">
        <Panel title="use() inside a condition">
          <ReaderWithUse skip={skip} />
          <button onClick={() => setSkip((s) => !s)}>
            {skip ? "read the context" : "skip the read"}
          </button>
        </Panel>
      </ThemeContext>

      <p style={{ color: "#666", fontSize: 13 }}>
        The last panel returns before calling use() when skipping — legal,
        because use() stores nothing on the fiber. Doing that with useContext
        would throw a Rules of Hooks error.
      </p>
    </div>
  );
}
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 119 of 119 decoded in the React.js track. One more won't hurt.

Back to track

Track complete

You decoded the whole React.js. Legend.

Pick another arena