#Sharing data upstream or between client components with a different parent server component
24 messages · Page 1 of 1 (latest)
You can use
- useContext hook
- Redux/Redux toolkit
- ReactQuery (insert data in child component and consume it at parent component)
I would recommend useContext.
+1 for useContext
can data be communicated upstream through server components by useContext?
what would that look like? what value do I provide?
in a traditional react app without server components I know I can useState and put value + setter into the context value, but I cant do that if im providing this context in a server component
No, server components by design encourage fetching all the data they need in the component itself and make use of the caching features instead of passing data to them.
Context does not work with server components.
the actual design is more like...
Part 1:
app/[market]/[language]/layout.tsx -> html > body > header > <languageselect> -> components/header/LanguageSelect.tsx
Part 2:
app/[market]/[language]/[[slug]]/page.tsx -> getMetadata() (or whatever that's called) provides the alternate URLs that I also need in language select
but that leaves me with no native way to move that data upstream I think
Make components/header/LanguageSelect.tsx a client component.
Export:
LanguageMeta: A component that accepts your metadata as props and usesuseContextto set it in auseEffect. The component can just returnnull.LanguageMetaProvider: A component, which simply wraps the context provider- Your
LanguageSelectcomponent
In app/[market]/[language]/layout.tsx:
<LanguageMetaProvider>
//...
<LanguageSelect/>
//...
{children}
//...
</LanguageMetaProvider>
In app/[market]/[language]/[[slug]]/page.tsx:
<LanguageMeta meta={getMetadata()}/>
Due to all 3 being exported from a client file, this works in server components.
LanguageMeta returns null, because it just acts as a wrapper to use the hook inside of a server component.
ooh I think I get it, this is using that server components can be used as children for client components. What would happen if I stored it in a ref instead of state?
(and set it first render instead of in an effect), would that just not work, or would it depend on 'execution order'?
I suspect the execution order would always be unfavorable, if it did matter 😦
Updating the ref won't rerender the page. An effect is necessary because it would cause a mismatch between server and client during hydration otherwise.
You can provide an initial value in your layout, which is then updated on the client in useEffect.
The effect and context are necessary because of client-side navigation. Without it, the metadata wouldn't change after the initial page load. Shared layouts are not updated on client-side navigation.
Though, maybe there's something else you can do, depending on how the getMetadata function works.
How does the function know which page you're on? Are you providing any parameters?
yeah the slug param
I have the setup with useEffect now, but still really would like to do this on initial render
This makes it easier. You won't need any context in this case, unless you want to pass this data down to somewhere.
Params are passed to the layout as a prop. You can directly use your getMetadata function with the slug in the layout server component and pass it to the LanguageSelect. The slug in the layout won't change after client-side navigation, so this is just for the initial value.
Inside your LanguageSelect component, you can use useParams to update the data in a useEffect on client-side navigation.
This requires your function to be working on both server and client. If it doesn't work on the client, you can create a route handler and fetch it from the client.
I'm somewhat confident that I wasnt getting the slug param in layout (thet [[slug]] directory has the same parent directory as this layout.tsx does)
And we're using ISR, so the "initial page load" almost certainly would be re-using the layout from a different page.
However, I am somewhat confident that paralel routes will actually do the trick