Sharing state between client components
Answered
Spectacled bear posted this in #help-forum
Spectacled bearOP
How do I share state between client components? My understanding is I have to create a common parent (client wrapper) for the client components, but this would require most of my page to be client side rendered and I want most of it to be server side rendered. I do not want to change the layout of the HTML/TSX, but still share state between my three client components. Below is a simplified version of my code:
export default function Page() { {/* <-- Server component */}
return (
<main>
<section>
<h1>My static header</h1>
<p>My static description</p>
<ClientComponent1 /> {/* <-- User performs a state change in ClientComponent1 */}
</section>
<div>
<div>
<ClientComponent2 />
</div>
</div>
<section>
<h2>My static subheader</h2>
<ClientComponent3 /> {/* <-- State change from ClientComponent1 is needed in ClientComponent3 */}
</section>
</main>
);
}Answered by Cinnamon Teal
What sort of data is stored in state in
Is it something that can be put in the URL as searchParams?
Since you want to keep the layout,
1. Depending on the data, you could put it in URL. So other components can read it from the URL.
2. Use React Context. Create a separate provider component with
Your page component and all other components will still stay as server components.
This is assuming this data is not needed to be stored in a database. Otherwise your
ClientComponent1?Is it something that can be put in the URL as searchParams?
Since you want to keep the layout,
1. Depending on the data, you could put it in URL. So other components can read it from the URL.
2. Use React Context. Create a separate provider component with
use client, and create state in it. Pass the state and state update function through context.<>
<main>
<ClientProvider>
<section>
<h1>My static header</h1>
<p>My static description</p>
<ClientComponent1 />
</section>
<div>
<ClientComponent2 />
</div>
<section>
<h2>My static subheader</h2>
<ClientComponent3 />
</section>
</ClientProvider>
</main>
</>ClientCompoent1 uses the state updater function to update the state. All other components read the updated state.Your page component and all other components will still stay as server components.
This is assuming this data is not needed to be stored in a database. Otherwise your
ClientComponent1 would update the database, and you refresh the route causing new data to be fetched and pass along to child components.4 Replies
Cinnamon Teal
What sort of data is stored in state in
Is it something that can be put in the URL as searchParams?
Since you want to keep the layout,
1. Depending on the data, you could put it in URL. So other components can read it from the URL.
2. Use React Context. Create a separate provider component with
Your page component and all other components will still stay as server components.
This is assuming this data is not needed to be stored in a database. Otherwise your
ClientComponent1?Is it something that can be put in the URL as searchParams?
Since you want to keep the layout,
1. Depending on the data, you could put it in URL. So other components can read it from the URL.
2. Use React Context. Create a separate provider component with
use client, and create state in it. Pass the state and state update function through context.<>
<main>
<ClientProvider>
<section>
<h1>My static header</h1>
<p>My static description</p>
<ClientComponent1 />
</section>
<div>
<ClientComponent2 />
</div>
<section>
<h2>My static subheader</h2>
<ClientComponent3 />
</section>
</ClientProvider>
</main>
</>ClientCompoent1 uses the state updater function to update the state. All other components read the updated state.Your page component and all other components will still stay as server components.
This is assuming this data is not needed to be stored in a database. Otherwise your
ClientComponent1 would update the database, and you refresh the route causing new data to be fetched and pass along to child components.Answer
Spectacled bearOP
Thanks for the answer, I really appreciate it.
In regards to option number 2, how come anything that is a child of ClientProvider not become part of that client component (thus client rendered)? For instance such as:
In regards to option number 2, how come anything that is a child of ClientProvider not become part of that client component (thus client rendered)? For instance such as:
<section>
<h1>My static header</h1>
<p>My static description</p>
<ClientComponent1 />
</section>@Spectacled bear Thanks for the answer, I really appreciate it.
In regards to option number 2, how come anything that is a child of ClientProvider not become part of that client component (thus client rendered)? For instance such as:
<section>
<h1>My static header</h1>
<p>My static description</p>
<ClientComponent1 />
</section>
Cinnamon Teal
Because you are not importing those server components into the Provider client component. You are just passing the server components through.
If you imported those server components into a client component, then they also gets included in the client bundle and becomes client components. But in this case it's not.
So all those component that are not marked explicitly with
This is a common pattern when you want to share client state app wide. A common example would be a
Worth checking the few example mentioned in this page: https://nextjs.org/docs/app/getting-started/server-and-client-components#context-providers
If you imported those server components into a client component, then they also gets included in the client bundle and becomes client components. But in this case it's not.
So all those component that are not marked explicitly with
use client will stay as server component, even though they are visually wrapped in a client component.This is a common pattern when you want to share client state app wide. A common example would be a
<ThemeProvider>.Worth checking the few example mentioned in this page: https://nextjs.org/docs/app/getting-started/server-and-client-components#context-providers
Spectacled bearOP
This makes sense now. Thank you!