From 980e3271cabce62a33ef0eae88f3ead6d1d4d789 Mon Sep 17 00:00:00 2001 From: Cesare Naldi Date: Thu, 16 May 2024 16:38:38 +0200 Subject: [PATCH] feat: add React Suspense support to useSearchPublications hook --- .changeset/lovely-dodos-prove.md | 7 ++ .../src/discovery/UseSearchPublications.tsx | 16 ++- .../react/src/discovery/useSearchProfiles.ts | 8 +- .../src/discovery/useSearchPublications.ts | 104 ++++++++++++++---- 4 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 .changeset/lovely-dodos-prove.md diff --git a/.changeset/lovely-dodos-prove.md b/.changeset/lovely-dodos-prove.md new file mode 100644 index 000000000..f10895af9 --- /dev/null +++ b/.changeset/lovely-dodos-prove.md @@ -0,0 +1,7 @@ +--- +"@lens-protocol/react": minor +"@lens-protocol/react-native": minor +"@lens-protocol/react-web": minor +--- + +**feat:** add React Suspense support to `useSearchPublications` hook diff --git a/examples/web/src/discovery/UseSearchPublications.tsx b/examples/web/src/discovery/UseSearchPublications.tsx index 5e522f40c..c3e09e676 100644 --- a/examples/web/src/discovery/UseSearchPublications.tsx +++ b/examples/web/src/discovery/UseSearchPublications.tsx @@ -1,8 +1,7 @@ import { LimitType, useSearchPublications } from '@lens-protocol/react-web'; -import { useState } from 'react'; +import { Suspense, startTransition, useState } from 'react'; import { PublicationCard } from '../components/cards'; -import { ErrorMessage } from '../components/error/ErrorMessage'; import { Loading } from '../components/loading/Loading'; import { useInfiniteScroll } from '../hooks/useInfiniteScroll'; @@ -11,17 +10,14 @@ type SearchResultsProps = { }; function SearchResults({ query }: SearchResultsProps) { - const { data, error, loading, hasMore, observeRef } = useInfiniteScroll( + const { data, hasMore, observeRef } = useInfiniteScroll( useSearchPublications({ query, limit: LimitType.Fifty, + suspense: true, }), ); - if (loading) return ; - - if (error) return ; - if (data.length === 0) { return

No publications found

; } @@ -48,7 +44,9 @@ export function UseSearchPublications() { const q = formData.get('query') as string | null; if (q) { - setQuery(q); + startTransition(() => { + setQuery(q); + }); } }; @@ -62,7 +60,7 @@ export function UseSearchPublications() {   - {query && } + }>{query && } ); } diff --git a/packages/react/src/discovery/useSearchProfiles.ts b/packages/react/src/discovery/useSearchProfiles.ts index 580c648d4..c7e940291 100644 --- a/packages/react/src/discovery/useSearchProfiles.ts +++ b/packages/react/src/discovery/useSearchProfiles.ts @@ -79,9 +79,11 @@ export function useSearchProfiles(args: UseSearchProfilesArgs): PaginatedReadRes * suspense: true, * }); * - * const search = startTransition(() => { - * setQuery('foo'); - * }); + * const search = () => { + * startTransition(() => { + * setQuery('foo'); + * }); + * }; * ``` * * @experimental This API can change without notice diff --git a/packages/react/src/discovery/useSearchPublications.ts b/packages/react/src/discovery/useSearchPublications.ts index 39b1d7ef0..385e2eb11 100644 --- a/packages/react/src/discovery/useSearchPublications.ts +++ b/packages/react/src/discovery/useSearchPublications.ts @@ -1,23 +1,37 @@ import { PrimaryPublication, PublicationSearchRequest, - useSearchPublications as useBaseSearchPublications, + PublicationSearchWhere, + SearchPublicationsDocument, } from '@lens-protocol/api-bindings'; import { useLensApolloClient } from '../helpers/arguments'; -import { PaginatedArgs, PaginatedReadResult, usePaginatedReadResult } from '../helpers/reads'; +import { PaginatedArgs, PaginatedReadResult } from '../helpers/reads'; +import { + SuspendablePaginatedResult, + SuspenseEnabled, + SuspensePaginatedResult, + useSuspendablePaginatedQuery, +} from '../helpers/suspense'; import { useFragmentVariables } from '../helpers/variables'; +/** + * {@link useSearchPublications} hook arguments + */ export type UseSearchPublicationsArgs = PaginatedArgs; +export type { PublicationSearchRequest, PublicationSearchWhere }; + /** - * Search for publications based on a defined criteria + * {@link useSearchPublications} hook arguments with Suspense support * - * @category Discovery - * @group Hooks - * @param args - {@link UseSearchPublicationsArgs} + * @experimental This API can change without notice + */ +export type UseSuspenseSearchPublicationsArgs = SuspenseEnabled; + +/** + * Search for publications based on a defined criteria * - * @example * Search for publications with content that contains "foo" * ```tsx * import { useSearchPublications } from '@lens-protocol/react'; @@ -41,7 +55,6 @@ export type UseSearchPublicationsArgs = PaginatedArgs; * } * ``` * - * @example * Search for audio post publications with content that matches a query * ```tsx * import { useSearchPublications } from '@lens-protocol/react'; @@ -72,22 +85,71 @@ export type UseSearchPublicationsArgs = PaginatedArgs; * ); * } * ``` + * + * @category Discovery + * @group Hooks */ +export function useSearchPublications( + args: UseSearchPublicationsArgs, +): PaginatedReadResult; + +/** + * Search for publications based on a defined criteria + * + * This signature supports [React Suspense](https://react.dev/reference/react/Suspense). + * + * ```tsx + * const { data } = useSearchPublications({ + * query: 'foo', + * suspense: true, + * }); + * + * console.log(data); + * ``` + * + * Use [startTransition](https://react.dev/reference/react/startTransition) to avoid to re-suspend the component. + * + * ```tsx + * const [query, setQuery] = useState('foo'); + * + * const { data } = useSearchPublications({ + * query, + * suspense: true, + * }); + * + * const search = () => { + * startTransition(() => { + * setQuery('bar'); + * }); + * }; + * ``` + * + * @experimental This API can change without notice + * @category Discovery + * @group Hooks + */ +export function useSearchPublications( + args: UseSuspenseSearchPublicationsArgs, +): SuspensePaginatedResult; + export function useSearchPublications({ - query, limit, + query, + suspense = false, where, -}: UseSearchPublicationsArgs): PaginatedReadResult { - return usePaginatedReadResult( - useBaseSearchPublications( - useLensApolloClient({ - variables: useFragmentVariables({ - query, - limit, - where, - statsFor: where?.metadata?.publishedOn, - }), +}: UseSearchPublicationsArgs & { suspense?: boolean }): SuspendablePaginatedResult< + PrimaryPublication[] +> { + return useSuspendablePaginatedQuery({ + suspense, + query: SearchPublicationsDocument, + options: useLensApolloClient({ + variables: useFragmentVariables({ + query, + limit, + where, + statsFor: where?.metadata?.publishedOn, }), - ), - ); + }), + }); }