Lifting State to parents with RSC's
Answered
Barbary Lion posted this in #help-forum
Barbary LionOP
If you have 2 sibling components that should share state, you should lift it to the parent.
But with RSC's often being the parent (server component) they can't use useState.
So I'm finding myself doing this architecture:
Parent (server) (fetches data)
child (client)(just a pure container to hold state for children)
(child)uses state from above
(child)uses state from above
Does this pattern make sense? Due to parent fetching data (server component), and can't hold state, you make a container child simply for the purpose of creating usestate and sharing with what would otherwise be the normal children components for the parent component.
When looking at a lot of examples showing RSC's you often see the background page being server component, with a few client components placed ontop of it. But in practice if they share any state, that model can't work ? They all need to really be in 1 client component ?
But with RSC's often being the parent (server component) they can't use useState.
So I'm finding myself doing this architecture:
Parent (server) (fetches data)
child (client)(just a pure container to hold state for children)
(child)uses state from above
(child)uses state from above
Does this pattern make sense? Due to parent fetching data (server component), and can't hold state, you make a container child simply for the purpose of creating usestate and sharing with what would otherwise be the normal children components for the parent component.
When looking at a lot of examples showing RSC's you often see the background page being server component, with a few client components placed ontop of it. But in practice if they share any state, that model can't work ? They all need to really be in 1 client component ?
Answered by Eric Burel
creating a component is free there's nothing wrong into crafting wrapper that just hold state or stuff like that, it's the way of doing things in React and usually happens quite "organically" like you see that the 2 components need the same state => it's time to craft a parent component or context to handle the state
15 Replies
Yes it makes sense the first client child can be a React context btw
creating a component is free there's nothing wrong into crafting wrapper that just hold state or stuff like that, it's the way of doing things in React and usually happens quite "organically" like you see that the 2 components need the same state => it's time to craft a parent component or context to handle the state
Answer
RSCs have no state they are rendered during the lifecycle of an HTTP request so UI state is always a matter handled by client components
similar setup showing how to pass data from the RSC to children, handling state is similar
American Crow
There is nothing wrong wit that concept as @Eric Burel already mentioned.
I want to expand a little bit on it, because it depends on your use case
1. Use the concept you described
2. You can have state in the form of query params (searchParams) in a server component.
That would make the state visible to the user but makes sense in some cases. Think of an ecommerce site
Now the server components serachParams hold
3. If it's just about the children having the same data from a fetch. You could also just have two server components and do the same fetch twice.
Nextjs will automatically memoize those requests and make sure there are no performance issues so the fetch is only run once. That concept is refered as
https://nextjs.org/docs/app/building-your-application/data-fetching/patterns#fetching-data-where-its-needed
I want to expand a little bit on it, because it depends on your use case
1. Use the concept you described
2. You can have state in the form of query params (searchParams) in a server component.
That would make the state visible to the user but makes sense in some cases. Think of an ecommerce site
products?color=blue&size=xlNow the server components serachParams hold
color and size which can be passed to client components which itself can manipulate those.3. If it's just about the children having the same data from a fetch. You could also just have two server components and do the same fetch twice.
Nextjs will automatically memoize those requests and make sure there are no performance issues so the fetch is only run once. That concept is refered as
fetch data where its needed, meaning as far out at the leaf as possible.https://nextjs.org/docs/app/building-your-application/data-fetching/patterns#fetching-data-where-its-needed
Thrianta
A note on
fetch data where needed is that it is automatically done with the fetch api, but I believe you need unstable_cache if you want to memoize your ORM fetches and etc@Thrianta A note on `fetch data where needed` is that it is automatically done with the `fetch` api, but I believe you need `unstable_cache` if you want to memoize your ORM fetches and etc
Next.js "unstable_cache" doesn't memoize, it does actually cache meaning it's shared across users and not just deduplicated for the current request
for memoization you'd want React "cache" only
To tell them aprt you can think "cache" is a React thing (so not shared across users, it doesn't operate at this scale, it's scoped to a single request = a single render step) and "unstable_cache" is a Next.js thing (it cares about requests, caching in the backend etc.)
for memoization you'd want React "cache" only
To tell them aprt you can think "cache" is a React thing (so not shared across users, it doesn't operate at this scale, it's scoped to a single request = a single render step) and "unstable_cache" is a Next.js thing (it cares about requests, caching in the backend etc.)
Thrianta
Perfect 👍🏼
@Thrianta A note on `fetch data where needed` is that it is automatically done with the `fetch` api, but I believe you need `unstable_cache` if you want to memoize your ORM fetches and etc
Barbary LionOP
Yes I'm using ORM fetches, so was a bit confused with caching, but after reading, it makes a lot of sense that ORM fetch caching is basically the route caching paradigm
@Eric Burel similar setup showing how to pass data from the RSC to children, handling state is similar
Barbary LionOP
Thank you for your reply! Appreciate
@American Crow There is nothing wrong wit that concept as <@769111741098622976> already mentioned.
I want to expand a little bit on it, because it depends on your use case
1. Use the concept you described
2. You can have state in the form of query params (searchParams) in a server component.
That would make the state visible to the user but makes sense in some cases. Think of an ecommerce site `products?color=blue&size=xl`
Now the server components serachParams hold `color` and `size` which can be passed to client components which itself can manipulate those.
3. If it's just about the children having the same data from a fetch. You could also just have two server components and do the same fetch twice.
Nextjs will automatically memoize those requests and make sure there are no performance issues so the fetch is only run once. That concept is refered as `fetch data where its needed`, meaning as far out at the leaf as possible.
https://nextjs.org/docs/app/building-your-application/data-fetching/patterns#fetching-data-where-its-needed
Barbary LionOP
Also thank you for the additional info, yes I've been playing around with searchParams, pretty cool, I don't yet understand how the server component knows to rerender the page if search params change.. But using searchParams for state that I'm happy to expose to client, DB data fetching was what I needed to pass to children, and found myself passing it through a child container first to get to the actual children
@Eric Burel Next.js "unstable_cache" doesn't memoize, it does actually cache meaning it's shared across users and not just deduplicated for the current request
for memoization you'd want React "cache" only
To tell them aprt you can think "cache" is a React thing (so not shared across users, it doesn't operate at this scale, it's scoped to a single request = a single render step) and "unstable_cache" is a Next.js thing (it cares about requests, caching in the backend etc.)
Barbary LionOP
Any chance you could give a tiny pseudo code example of this, as I'm fetching data with ORM (supabase's orm), and not 100% understanding when or when it will not memoize the data
@Barbary Lion Also thank you for the additional info, yes I've been playing around with searchParams, pretty cool, I don't yet understand how the server component knows to rerender the page if search params change.. But using searchParams for state that I'm happy to expose to client, DB data fetching was what I needed to pass to children, and found myself passing it through a child container first to get to the actual children
American Crow
you welcome. The "trick" is to
The push makes it so the the request goes back to the server component and the new values are in its
router.push to the new queryparams in the client component whenever the state changes. E.g. const [selectedColor, setSelectedColor] = usteState("blue")
const [selectedSize, setSelectedSize] = usteState("xl")
useEffect(()=> {
router.push(`?color=${selectedColor}&size={selectedSize}`)
},[selectedColor,selectedSize, router]The push makes it so the the request goes back to the server component and the new values are in its
searchParamsBarbary LionOP
Ah that makes perfect sense! Thanks