From ed721c0a1fb76c53c74dc3384a88ec2e50c115da Mon Sep 17 00:00:00 2001 From: JavidSumra Date: Mon, 9 Dec 2024 12:41:40 +0530 Subject: [PATCH] Add Documentation for useInfiniteQuery hook --- .../care/development/data-fetching-in-care.md | 110 +++++++++++++++++- 1 file changed, 106 insertions(+), 4 deletions(-) diff --git a/docs/care/development/data-fetching-in-care.md b/docs/care/development/data-fetching-in-care.md index 3bf9536..d7200e1 100644 --- a/docs/care/development/data-fetching-in-care.md +++ b/docs/care/development/data-fetching-in-care.md @@ -66,9 +66,9 @@ Now let's say an API endpoint has a variable in the URL (example: `GET /example/ ```jsx export default function Component(props: { consultationId: string }) { const { data } = useQuery(MedicineRoutes.prescriptions.list, { - pathParams: { + pathParams: { consultation_external_id: props.consultationId, - } + }, }); return ; @@ -90,6 +90,108 @@ const MedicineRoutes = { } ``` +## Introduction to `useInfiniteQuery` + +`useInfiniteQuery` is a custom hook built on top of `useQuery` for handling paginated API requests that support infinite scrolling or loading more data as needed. It facilitates fetching paginated data, managing the state of items, and ensuring that duplicate items are removed when fetching new pages of results. + +### Basic Usage + +Here’s an example of how to use `useInfiniteQuery` to fetch paginated data and load additional pages: + +```jsx +export default function Page() { + const { items, loading, fetchNextPage, hasMore } = useInfiniteQuery( + MedicineRoutes.prescriptions.list, + { + deduplicateBy: (item) => item.id, // Deduplicate based on a unique identifier + } + ); + + // Display a loading indicator while data is being fetched + if (loading) { + return ; + } + + // Render the list of items + return ( + <> + + + {/* Button to load more data if there are more items to fetch */} + {hasMore && } + + ); +} +``` + +In the example above: + +- `items` is the list of fetched items that is updated as new pages of data are loaded. +- `loading` indicates whether a request is currently in progress. +- `fetchNextPage` is the function that triggers the loading of the next page. +- `hasMore` tells you if there are more items to load based on the total count of items and the length of the fetched items. + +### Arguments + +`useInfiniteQuery` accepts the following arguments: + +1. **`route`** (required): A route definition that describes the API endpoint, HTTP method, and response structure, just like with `useQuery`. The route should expect a paginated response with the `PaginatedResponse` structure. + + Example route definition: + + ```ts + const MedicineRoutes = { + prescriptions: { + list: { + path: "/api/v1/consultation/{consultation_external_id}/prescriptions/", + method: "GET", + TRes: Type>(), + }, + }, + }; + ``` + +2. **`options`**: An object that allows customization of the query. It includes the following properties: + + - **`deduplicateBy`**: **Required**. A function that extracts a unique identifier from each item to prevent duplicate items when new pages are loaded. This function ensures that items are only shown once, even if the same data appears in multiple pages. + + Example of passing options: + + ```ts + const options = { + deduplicateBy: (item) => item.id, // Deduplicate based on a unique identifier + }; + ``` + +### Key Return Values + +The `useInfiniteQuery` hook returns an object containing the following properties: + +- **`items`**: An array of items fetched so far (combined from multiple pages). The array is updated as more data is loaded. +- **`loading`**: A boolean indicating if the request is in progress. +- **`fetchNextPage`**: A function to load the next page of results. +- **`refetch`**: A function to refetch the data (same as `useQuery`). +- **`totalCount`**: The total count of items available (e.g., in a paginated result). +- **`hasMore`**: A boolean indicating whether there are more items to load based on the total count and the current number of fetched items. + +### Example of Paginated API Route + +A typical paginated response from the API might look like this: + +```json +{ + "results": [ + { "id": 1, "name": "Prescription 1" }, + { "id": 2, "name": "Prescription 2" } + ], + "count": 100 +} +``` + +### Handling Pagination + +`useInfiniteQuery` handles pagination by keeping track of the `offset` (the number of items already loaded) and appending new items as additional pages are fetched. The `fetchNextPage` function increments the offset to load the next set of results. + ## Performing non-GET requests Let's say we want to submit a form, here we can make use of `request`. @@ -103,7 +205,7 @@ export default function Component(props: { patientId: string }) { if (validate(data)) { return; } - + setIsProcessing(true); const { res, errors } = await request(routes.consultation.create, { pathParams: { patient_id: props.patientId }, @@ -113,7 +215,7 @@ export default function Component(props: { patientId: string }) { } return ( -
{ e.preventDefault(); handleSubmit();