Eliot Hertenstein
Eliot Hertenstein

Reputation: 411

How to share state between react client components with a parent server component?

In my next.js app I have a page with two components: A and B.

// page.tsx

import A from './A'
import B from './B'

const Page = () => {
  return (
    <div>
      <A />
      <B />
    </div>
  )
}

export default Page
// A.tsx

'use client';

import { useState } from 'react'

const A = () => {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>you clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>click me</button>
    </div>
  )
}

export default A
// B.tsx

'use client';

import { useState } from 'react'

const B = () => {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>you clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>click me</button>
    </div>
  )
}

export default B

Let's assume that I want to render Page statically on the server. However, I also would like to implement state on the client side. What is the best way to synchronize the state of A and B while keeping Page as a server component?

Upvotes: 4

Views: 1007

Answers (1)

Farouk Faiz
Farouk Faiz

Reputation: 31

You can make use of the context API for that. You can render your context provider it in a client component and inject it in your page:

// page.tsx
// ...

const Page = () => {
  return (
    <MyProvider>
      <A />
      <B />
    </MyProvider>
  )
}

// ...

The context can look something like this:

// CountProvider.tsx

"use client";

interface CountContextType {
  count: number;
  setCount: Dispatch<SetStateAction<number>>;
}

export const CountContext = createContext<CountContextType>({
  count: 0,
  setCount: () => {},
});

export default function CountProvider({children}: {children: React.ReactNode}) {
  const [count, setCount] = useState<number>(0);
  return (
    <CountContext.Provider value={{ count, setCount }}>
      {children}
    </CountContext.Provider>
  );
}

Finally, you can access and modify the same context count from your child components, effectively sharing the state. For example, in the component A, instead of using:

const [count, setCount] = useState(0);

You can use:

const {count, setCount} = useContext(CountContext);

Upvotes: 2

Related Questions