Reputation: 33
I am working on a Web App which is made using Next JS 15 ( App Router ).
It has a Dashboard in which there are many different widgets which shows data, which is fetched from API. All these widgets have it's own API to fetch data from. I can easily fetch data in their own server components and show Skeleton while the data is being fetched. But the problem here is I have many different filters too in each APIs. I have UI components in each widget to add filter to that particular widget so I need to fetch data from the API again when the user applies some filters. Now this is client interaction and Server Components doesn't support that. So I keep the UI component to apply filters as Client component but now how do I get the applied filters inside the server component and fetch new data based on that?
props
(provided by Next JS). But when I set the filters in search params, there is a slight delay between the user interaction and actual setting of the search param. This feels less interactive and laggy.Below is the server component in which I fetch data.
import fetchData from "@/lib/actions/fetch"
export default async function TotalEarningWidget({searchParams}) {
const currentSearchParams = await searchParams
const apiSearchParams = new URLSearchParams()
apiSearchParams.append('filter', currentSearchParams.filter)
// Fake API call using a helper function which handles the API call
// I am not using any third party library for this, just a simple fetch API
const totalEarningsData = await fetchData(`/total-earnings?${apiSearchParams.toString()}`)
return <div>{/* ... */}</div>
}
And here is the client component from which I set filters to search params.
"use client"
import { useRouter, useSearchParams } from "next/navigation"
export default function FilterComponent() {
const { replace } = useRouter()
const currentSearchParams = useSearchParams()
return (
<div>
<select
defaultValue={currentSearchParams.get("filter")?.toString()}
onChange={e => replace(`?filter=${e.target.value}`)}
>
<option value="1">Filter Option 1</option>
<option value="2">Filter Option 2</option>
<option value="3">Filter Option 3</option>
</select>
</div>
)
}
useState
hook so I get the applied filter instantly and then set that applied filter to the URL so that I don't lose the applied filters if I refresh the page. I fetch the data Client Side using server actions so they don't expose my actual API URL. I don't know if this is a good approach but this works. But there is still an issue, when the dashboard is loading first time, it take a bit longer than it used to take when I was fetching data on server side. Is this because I switched to client side data fetching? Or is it something else that I might be missing?Below is the client component in which I store applied filters and fetch data according to that.
"use client"
import { useSearchParams } from "next/navigation"
import { useEffect, useState } from "react"
export default function TotalEarningWidget({ searchParams }) {
const [data, setData] = useState()
const currentSearchParams = useSearchParams()
const [appliedFilters, setAppliedFilters] = useState({
filter: currentSearchParams.get("filter")?.toString(),
})
useEffect(() => {
const fetchedData = fetchDataAction(appliedFilters.filter)
setData(fetchedData)
}, [appliedFilters])
const handleFilterChange = filterToSet => {
setAppliedFilters({ filter: filterToSet })
}
return <div>{/* ... */}</div>
}
Upvotes: 2
Views: 49