Next.js Discord

Discord Forum

Communication between client and server components

Answered
Tomistoma posted this in #help-forum
Open in Discord
TomistomaOP
Hey, guys! Suppose you have a client component like a filter or a selector and you want to render some server components generated from MDX files (using next-mdx-remote, so, asynchronous). How would you make the communication between the filter/selector and the server components if the latter can't use hooks to rerender according to the changes on the filter/selector? Without using useEffect, if possible
Answered by fuma
It's impossible because server components can't be re-rendered on the client side.
Instead, just pass the data from a server component and render it with client components.
View full answer

20 Replies

It's impossible because server components can't be re-rendered on the client side.
Instead, just pass the data from a server component and render it with client components.
Answer
Then, you can implement the filter/selector with a Context or the way you prefer
If you must do it with server components, my idea is to wrap your server component in a client component, like:

<FilterElement data={data}>
  <ServerComponent />
</FilterElement>


where FilterElement is a client component that consumes the context and displays its children (the server component) conditionally.
Since you can pass server components as prop
My currently preferred method is to make use of the URLs searchParams.

In your filter element, you can update the searchParams, then your page.tsx can receive those new params and do any filtering based on that
However, using it will opt the page into dynamic rendering.
so be careful when doing this
@fuma If you must do it with server components, my idea is to wrap your server component in a client component, like: tsx <FilterElement data={data}> <ServerComponent /> </FilterElement> where `FilterElement` is a client component that consumes the context and displays its children (the server component) conditionally.
TomistomaOP
Let me see if I've understood correctly. It would be something like this?
// page.tsx export default async function Page() { const products = await productsRepo.getAll() return <ClientSideComponentWithFilter products={products} renderReactNode={(p: Product) => <ServerSideComponent product={p} />} /> }

// ClientSideComponentWithFilter.tsx export default function ClientSideComponentWithFilter({ products, renderReactNode }: ClientSideComponentWithFilterProps) { const [category, setCategory] = useState<'All' | 'Wearables' | 'Eletronics'>('All') const handleCategoryChange = (value: string) => { const parseRes = // ... parse with zod if (parseRes.success) setCategory(parseRes.data) } return ( <> <Selector items={['All', 'Wearables', 'Eletronics'] onSelectionChange={handleCategoryChange}} /> {products .filter(p => category === 'All' || p.category === category) .map(p => renderReactNode(p))} // using a render function that returns React.ReacNode since client side component can't import server side component </> ) }
Perhaps not the best example or use of the method, but here is mine: https://github.com/leonlarsson/leon-home/blob/main/app/(main)/projects/page.tsx

The <Search /> component is a client component that writes to the URL. page.tsx (server) reads the searchParams, and I filter based on that and pass to my server component to display that filtered data
@Mozzy Perhaps not the best example or use of the method, but here is mine: <https://github.com/leonlarsson/leon-home/blob/main/app/(main)/projects/page.tsx> The <Search /> component is a client component that writes to the URL. page.tsx (server) reads the searchParams, and I filter based on that and pass to my server component to display that filtered data
TomistomaOP
That's very interesting. I didn't know the page could receive data from metadata like that. Thanks a lot for sharing! Is there 100% of certainty that generateMetadata call is finished before the page function?
@Tomistoma That's very interesting. I didn't know the page could receive data from metadata like that. Thanks a lot for sharing! Is there 100% of certainty that generateMetadata call is finished before the page function?
generateMetadata is irrelevant to the filtering discussion. That's just to build the metadata for the page (SEO purposes and whatnot)
@Mozzy `generateMetadata` is irrelevant to the filtering discussion. That's just to build the metadata for the page (SEO purposes and whatnot)
TomistomaOP
Hm, I think I'll need to recheck the code and study more about metadata, then. I thought the page searchParams input that is used to filter was only available to use because of the presence of generateMetadata.
generateMetadata is solely for generating the page's metadata

On line 24 in that file you can see that I get the searchParams and then use them to filter
If you want to see it in action: https://leonlarsson.com/projects
@Mozzy If you want to see it in action: <https://leonlarsson.com/projects>
TomistomaOP
Very nice website, congratz! I read more about this searchParams which I didn't know about. There's the problem of making the page dynamic, as fuma said before and now I understood. I'd like to have a static page if possible.
@Mozzy Perhaps not the best example or use of the method, but here is mine: <https://github.com/leonlarsson/leon-home/blob/main/app/(main)/projects/page.tsx> The <Search /> component is a client component that writes to the URL. page.tsx (server) reads the searchParams, and I filter based on that and pass to my server component to display that filtered data
Very interesting, please tell me if i understood this correctly
page.tsx is a server component, and search.tsx is a client component. We can access search params in both server and client components. So when i type anything into the search box, router.replace inside onchange in search.tsx updates the params, which results in re-rendering of the whole page.tsx on server side with the new params. And since params are changed, the useeffect inside search.tsx is also triggered.
Is this correct? Im still very new to Next.js