From bd2a450c284d8c20aaa69860f82d9ff93f4f1f38 Mon Sep 17 00:00:00 2001 From: John Ballesteros Date: Thu, 15 Aug 2024 13:32:38 +0800 Subject: [PATCH 1/5] refactor: prefetch grant-details from grant-list --- .../components/grant-list/use-grant-list.ts | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/grants/components/grant-list/use-grant-list.ts b/src/grants/components/grant-list/use-grant-list.ts index 54c6ab1..3fbbba8 100644 --- a/src/grants/components/grant-list/use-grant-list.ts +++ b/src/grants/components/grant-list/use-grant-list.ts @@ -1,10 +1,24 @@ +import { useEffect } from 'react'; import { useInView } from 'react-intersection-observer'; +import { getQueryClient } from '@/shared/utils/get-query-client'; + +import { grantQueryKeys } from '@/grants/core/query-keys'; +import { getGrantDetails } from '@/grants/data/get-grant-details'; import { useGrantListQuery } from '@/grants/hooks/use-grant-list-query'; export const useGrantList = () => { - const { data, error, fetchNextPage, hasNextPage, isPending, isFetching } = - useGrantListQuery(); + const queryClient = getQueryClient(); + + const { + data, + error, + fetchNextPage, + hasNextPage, + isPending, + isFetching, + isSuccess, + } = useGrantListQuery(); // Next page fetch on scroll const { ref: inViewRef } = useInView({ @@ -14,6 +28,20 @@ export const useGrantList = () => { }, }); + // Prefetch grant details + useEffect(() => { + if (isSuccess && data) { + const items = data.pages.flatMap((d) => d.data); + for (const item of items) { + const { id } = item; + queryClient.prefetchQuery({ + queryKey: grantQueryKeys.details(id), + queryFn: () => getGrantDetails(id), + }); + } + } + }); + return { grants: data?.pages.flatMap((d) => d.data) ?? [], error, From c9c8f037310a4608ad9f274ece4a76c7849487d3 Mon Sep 17 00:00:00 2001 From: John Ballesteros Date: Thu, 15 Aug 2024 13:46:37 +0800 Subject: [PATCH 2/5] refactor: ssr initial items for grant-list --- src/grants/pages/grant-list-page.tsx | 42 ++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/grants/pages/grant-list-page.tsx b/src/grants/pages/grant-list-page.tsx index e8b7821..856795c 100644 --- a/src/grants/pages/grant-list-page.tsx +++ b/src/grants/pages/grant-list-page.tsx @@ -1,11 +1,43 @@ +import { dehydrate, HydrationBoundary } from '@tanstack/react-query'; + +import { getQueryClient } from '@/shared/utils/get-query-client'; + +import { grantQueryKeys } from '@/grants/core/query-keys'; +import { getGrantDetails } from '@/grants/data/get-grant-details'; +import { getGrantList } from '@/grants/data/get-grant-list'; import { GrantList } from '@/grants/components/grant-list/grant-list'; -export const GrantListPage = () => { - // TODO: React-Query SSR grant list +// TODO: Check if need to use search params(filter related), if so need to force dynamic + +export const GrantListPage = async () => { + const queryClient = getQueryClient(); + + const [grantListResult] = await Promise.all([ + // Prefetch list + queryClient.fetchInfiniteQuery({ + queryKey: grantQueryKeys.list(''), + queryFn: async ({ pageParam }) => getGrantList(pageParam), + initialPageParam: 1, + }), + ]); + + // Prefetch details for each grant item + await Promise.all( + grantListResult.pages + .flatMap((page) => page.data) + .map(({ id }) => + queryClient.prefetchQuery({ + queryKey: grantQueryKeys.details(id), + queryFn: () => getGrantDetails(id), + }), + ), + ); return ( -
- -
+ +
+ +
+
); }; From 9a1727e25e1906259388c23dd132a76033d06b17 Mon Sep 17 00:00:00 2001 From: John Ballesteros Date: Thu, 15 Aug 2024 15:14:50 +0800 Subject: [PATCH 3/5] refactor: ssr initial items for grantee-list which includes default grantee-card --- src/app/grants/[grantId]/@list/page.tsx | 39 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/app/grants/[grantId]/@list/page.tsx b/src/app/grants/[grantId]/@list/page.tsx index 8f4ed60..b3d87e5 100644 --- a/src/app/grants/[grantId]/@list/page.tsx +++ b/src/app/grants/[grantId]/@list/page.tsx @@ -1,13 +1,46 @@ +import { dehydrate, HydrationBoundary } from '@tanstack/react-query'; + +import { getQueryClient } from '@/shared/utils/get-query-client'; + +import { grantQueryKeys } from '@/grants/core/query-keys'; +import { getGranteeDetails } from '@/grants/data/get-grantee-details'; +import { getGranteesList } from '@/grants/data/get-grantees-list'; import { GranteeList } from '@/grants/components/grantee-list'; interface Props { params: { grantId: string }; } -const ParallelGranteeList = ({}: Props) => { - // TODO: React-Query SSR grantee list +const ParallelGranteeList = async ({ params: { grantId } }: Props) => { + const queryClient = getQueryClient(); + + const [granteeListResult] = await Promise.all([ + // Prefetch list + queryClient.fetchInfiniteQuery({ + queryKey: grantQueryKeys.grantees(grantId, ''), + queryFn: async ({ pageParam: page }) => + getGranteesList({ page, grantId }), + initialPageParam: 1, + }), + ]); + + // Prefetch details for each grantee item + await Promise.all( + granteeListResult.pages + .flatMap((page) => page.data) + .map(({ id }) => + queryClient.prefetchQuery({ + queryKey: grantQueryKeys.grantee(id), + queryFn: () => getGranteeDetails(id), + }), + ), + ); - return ; + return ( + + + + ); }; export default ParallelGranteeList; From 63847d8bc03a38fb19a8643ce9e445c477fefcda Mon Sep 17 00:00:00 2001 From: John Ballesteros Date: Thu, 15 Aug 2024 15:15:34 +0800 Subject: [PATCH 4/5] chore: smol cleanup --- src/shared/utils/get-query-client.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shared/utils/get-query-client.ts b/src/shared/utils/get-query-client.ts index dc0fa65..a925d40 100644 --- a/src/shared/utils/get-query-client.ts +++ b/src/shared/utils/get-query-client.ts @@ -17,12 +17,12 @@ export const getQueryClient = () => { if (typeof window === 'undefined') { // Server: always make a new query client return makeQueryClient(); - } else { - // Browser: make a new query client if we don't already have one - // This is very important so we don't re-make a new client if React - // supsends during the initial render. This may not be needed if we - // have a suspense boundary BELOW the creation of the query client - if (!browserQueryClient) browserQueryClient = makeQueryClient(); - return browserQueryClient; } + + // Browser: make a new query client if we don't already have one + // This is very important so we don't re-make a new client if React + // supsends during the initial render. This may not be needed if we + // have a suspense boundary BELOW the creation of the query client + if (!browserQueryClient) browserQueryClient = makeQueryClient(); + return browserQueryClient; }; From ebebcbe30cb114cd62ad3cba4690365388e3e941 Mon Sep 17 00:00:00 2001 From: John Ballesteros Date: Thu, 15 Aug 2024 18:15:39 +0800 Subject: [PATCH 5/5] refactor: only prefetch first item on the grantee list in grant-layout page --- src/app/grants/[grantId]/@list/page.tsx | 31 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/app/grants/[grantId]/@list/page.tsx b/src/app/grants/[grantId]/@list/page.tsx index b3d87e5..d2986a0 100644 --- a/src/app/grants/[grantId]/@list/page.tsx +++ b/src/app/grants/[grantId]/@list/page.tsx @@ -4,6 +4,7 @@ import { getQueryClient } from '@/shared/utils/get-query-client'; import { grantQueryKeys } from '@/grants/core/query-keys'; import { getGranteeDetails } from '@/grants/data/get-grantee-details'; +import { getGranteeProject } from '@/grants/data/get-grantee-project'; import { getGranteesList } from '@/grants/data/get-grantees-list'; import { GranteeList } from '@/grants/components/grantee-list'; @@ -24,17 +25,29 @@ const ParallelGranteeList = async ({ params: { grantId } }: Props) => { }), ]); - // Prefetch details for each grantee item - await Promise.all( - granteeListResult.pages - .flatMap((page) => page.data) - .map(({ id }) => + // Prefetch data for first item only (default for the page enough for seo) + const grantee = granteeListResult.pages.flatMap((page) => page.data).at(0); + if (grantee) { + // Prefetch grantee details + const promises = [ + queryClient.prefetchQuery({ + queryKey: grantQueryKeys.grantee(grantee.id), + queryFn: () => getGranteeDetails(grantee.id), + }), + ]; + + // Prefetch first project details + if (grantee.projects.length > 0) { + promises.push( queryClient.prefetchQuery({ - queryKey: grantQueryKeys.grantee(id), - queryFn: () => getGranteeDetails(id), + queryKey: grantQueryKeys.project(grantee.projects[0]), + queryFn: () => getGranteeProject(grantee.projects[0]), }), - ), - ); + ); + } + + await Promise.all(promises); + } return (