Setting the file. One moment.
Use Collection · Wix Headless Fast · wix/skills · Skills Docs
ContentsBack to the top of the page references/cms/app/hooks/cms/useCollection.ts
references/cms/app/hooks/cms/ useCollection.ts
TypeScript · 83 lines · 3 KB
10
filters
?:
CmsFilter
[];
11 sort ?: CmsSort [];
12 /** Page size (default 20). */
13 limit ?: number ;
14 /** Reference field keys to inline as full items. */
15 include ?: string [];
16 /** Server-fetched first page — must come from the SAME query (filters/sort/limit/include). */
17 initialItems ?: CmsItem [];
18 /** The server fetch's hasNext. Omitted → inferred (a full first page ⇒ assume more). */
19 initialHasNext ?: boolean ;
20 }
21
22 export interface UseCollection {
23 /** null while the first load is in flight — render skeletons, not an empty state. */
24 items : CmsItem [] | null ;
25 hasNext : boolean ;
26 loadMore : () => void ;
27 loadingMore : boolean ;
28 error : string | null ;
29 }
30
31 export function useCollection ( collectionId : string , options : UseCollectionOptions = {}) : UseCollection {
32 const { filters , sort , limit = 20 , include , initialItems , initialHasNext } = options;
33 // Query identity by value — Dates in filters serialize to ISO, so this is stable.
34 const key = JSON . stringify ([collectionId, filters ?? null , sort ?? null , limit, include ?? null ]);
35 const initialKey = useRef < string | null >(initialItems ? key : null );
36 const [ items , setItems ] = useState < CmsItem [] | null >(initialItems ?? null );
37 const [ hasNext , setHasNext ] = useState < boolean >(
38 initialHasNext ?? (initialItems ? initialItems. length >= limit : false ),
39 );
40 const [ loadingMore , setLoadingMore ] = useState ( false );
41 const [ error , setError ] = useState < string | null >( null );
42 const itemsRef = useRef < CmsItem [] | null >(items);
43 itemsRef.current = items;
44
45 useEffect (() => {
46 if (initialKey.current === key) return ; // the SSR pass already answered this exact query
47 initialKey.current = null ;
48 let alive = true ;
49 setItems ( null );
50 setError ( null );
51 queryItems (collectionId, { filters, sort, limit, include })
52 . then (( page ) => {
53 if ( ! alive) return ;
54 setItems (page.items);
55 setHasNext (page.hasNext);
56 })
57 . catch (( e ) => {
58 if ( ! alive) return ;
59 setItems ([]);
60 setError (e instanceof Error ? e.message : String (e));
61 });
62 return () => {
63 alive = false ;
64 };
65 // eslint-disable-next-line react-hooks/exhaustive-deps
66 }, [key]);
67
68 const loadMore = useCallback (() => {
69 const current = itemsRef.current;
70 if ( ! current || loadingMore) return ;
71 setLoadingMore ( true );
72 queryItems (collectionId, { filters, sort, limit, include, skip: current. length })
73 . then (( page ) => {
74 setItems ([ ... (itemsRef.current ?? []), ... page.items]);
75 setHasNext (page.hasNext);
76 })
77 . catch (( e ) => setError (e instanceof Error ? e.message : String (e)))
78 . finally (() => setLoadingMore ( false ));
79 // eslint-disable-next-line react-hooks/exhaustive-deps
80 }, [key, loadingMore]);
81
82 return { items, hasNext, loadMore, loadingMore, error };
83 }