Next.js Discord

Discord Forum

Passing Props Between Client and Server Components

Unanswered
Sweat bee posted this in #help-forum
Open in Discord
Sweat beeOP
Looking to get some guidance on the correct approach to pass props from a client component to a server component in NextJS 14 app router.

My use case:

I have a current Page.tsx in the root of /app that is a server component (default) and is fetching data from a Xata DB (SDK). I current have a search bar using searchParams within that same file to query the data in the URL "q?="

const xata = getXataClient();

export default async function Card({ searchParams }: { searchParams: { q: string } }) {
  let cards = null;
  if (searchParams.q) {
    const { records } = await xata.db.Network.search(searchParams.q, { 
      fuzziness: 1,
      boosters: [{ valueBooster: { column: 'PremiumMember', value: true, factor: 5 } }]
    }
    );
    cards = records;
  } else {
    cards = await xata.db.Network.filter({ProfileActive: true}).getMany({
      pagination: { size: 24 },
      fetchOptions: { next: { revalidate: "60" } },
    });
  }


This obviously works fine but does not feel "fast".

In order to search you have to hit enter to send the q request to the server and back. This causes a page refresh which also scrolls the users potentially elsewhere. Although still fairly quick it does not feel instant like other examples I've seen generally.

I'm wondering if refactoring this search bar out to a client component and passing down the q props to the page file would yield a "snappier" searching experience? This is stretching some of my React/NextJS knowledge but the leap I'm making is that since the Page.tsx data was fetched on the server, then it should be cached for the page session. Thus allowing the passed client search props to filter already cached data. Therefore snappy?

I may be missing a few links here. Would appreciate any guidance on if/how this pattern is supposed to work 🙏

16 Replies

Yes next has a tutorial even on how to incorporate a search bar. The reason you're getting a refresh is, i assume, that your browser is doing a regular submit, so forcing a browser refresh, You need to have it that:
<form onSubmit={(e) => { 
 e.preventDefault();
router.push(`url&${someFunctionToEncodeYourSearchParams(e)}`);}}>
   <input />
</form>

As we have custom javascript, the search bar itself needs to be a client component.
Here's the tut:
https://nextjs.org/learn/dashboard-app/adding-search-and-pagination
For my endpoint I put the search bar, filters, other stuff inside of layout.tsx and then only the rsc/search results & pagination are inside of pages.tsx - layout.tsx is not refreshed nor updated on url changes and it works really nicely
Sweat beeOP
Ah ok! So I was on the right track. And placing it in the layout makes sense. I would need refactor my case a bit to create a sub layout file/route then as I only want the search on a certain page. I guess though the actual input form is still a client component that is imported into the layout I want it displayed in?

Either way this was exactly what I was looking for! Thanks so much for your insight!
As a followup, this approach would still not be what I call live type filtering. Because even though the search is a client component, its still using a form/onsubmit to pass the query to the server data set? Is it much different to get a dynamic search that would need debounce protection?
or use window.location.search like [this](https://github.com/vercel/nextjs-postgres-nextauth-tailwindcss-template/blob/main/app/search.tsx) example if you don't need the searchParams on rendering
Sweat beeOP
Ah ok thanks for the example link. I will give the router push a try. The Learn NextJS also talks about how to handle the debounce.

So on the server side where the data was fetch. When a user inputs a search term (either keystroke or whole term input) how does NextJS handle what segment of the data is queried? For example, in my app, my data is fetched from the DB but I have a limit so that only the first 24 rows are returned. What happens when a search term is entered? is the data from the first 24 thrown out to search the whole DB or some sort of hybrid action? I'm curious for the purpose of seeing how many extra requests might be made to the DB.
@Ray it depend on how you fetch the data from DB, you could use `unstable_cache` function to cache the query result to reduce the load on DB. and you could use javascript to debounce the request. [use-debounce](<https://www.npmjs.com/package/use-debounce#debounced-callbacks>) is good for that
Sweat beeOP
I'm using the Xata SDK which currently is not playing nice with NextJS caching options lol But good to know. and yes I saw the use-debounce npm package in the tutorial.

Thanks for your insight!
@Sweat bee I'm using the Xata SDK which currently is not playing nice with NextJS caching options lol But good to know. and yes I saw the use-debounce npm package in the tutorial. Thanks for your insight!
oh yea, just saw that. I think you could try this
xata.db.Network.filter({ProfileActive: true}).getMany({
      pagination: { size: 24 },
      fetchOptions: { next: { revalidate: "60", tag: ["result"] }

then use revalidateTag to update the cache after some mutation revalidateTag("result")
@Ray or just using `revalidate: 60`
Sweat beeOP
I've tried the revalidate: 60 but cannot get a cache HIT to happen. I've spoken with the Xata team and they also can't get a cache hit. I think their team is looking into it.
Sweat beeOP
ah ok I will give that a try. Its a shame cause their SDK is very easy to use which is why I'm trying to available switching to a plain fetch to their API.