Search code examples
reactjsreact-contextastrojs

How to use React context in Astro. Minimal case


I have made a minimal case with the following components:

1. The context

// TestContext.jsx
import { createContext, useContext, useState } from "react";

const TestContext = createContext();

export const useTestContext = () => useContext(TestContext);

export const TestProvider = ({ children }) => {
  const [testValue, setTestValue] = useState(0);

  const changeValue = () => {
    setTestValue(testValue + 1);
  };

  return (
    <TestContext.Provider value={{ testValue, changeValue }}>
      {children}
    </TestContext.Provider>
  );
};

2. The Astro layout

// Layout.astro
import { TestProvider } from "../components/TestContext.jsx";
import Hello from "../components/Hello.jsx";

<TestProvider>
    <Hello client:load />
</TestProvider>

3. The child component

// Hello.jsx
import { useTestContext } from "./TestContext";

export default function Hello() {
  const { testValue, changeValue } = useTestContext();

  return (
    <div>
      <h1>Hello</h1>
      <p>Test Value: {testValue}</p>
      <button onClick={changeValue}>Change Value</button>
    </div>
  );
}

I get testValue as undefined:

[error] Cannot destructure property 'testValue' of '__vite_ssr_import_1__.useTestContext(...)' as it is undefined.

Solution

  • I think I found the cause in the astro documentation:

    "When building an Astro website with islands architecture / partial hydration, you may have run into this problem: I want to share state between my components.

    UI frameworks like React or Vue may encourage “context” providers for other components to consume. But when partially hydrating components within Astro or Markdown, you can’t use these context wrappers.

    Astro recommends a different solution for shared client-side storage: Nano Stores."

    https://docs.astro.build/en/core-concepts/sharing-state/