@@ -21,11 +21,17 @@ import useSWRMutation from 'swr/mutation';
2121
2222import { createClient } from './client/client' ;
2323import { PetSchema } from './client/schemas.gen' ;
24+ import { getInventory } from './client/sdk.gen' ;
2425import {
2526 addPetMutation ,
27+ findPetsByStatusKey ,
28+ findPetsByStatusOptions ,
29+ getInventoryKey ,
2630 getPetByIdOptions ,
31+ loginUserKey ,
2732 updatePetMutation ,
2833} from './client/swr.gen' ;
34+ // import { getPetByIdKey } from './client/swr.gen'; // For Pattern 2 example
2935import type { Pet } from './client/types.gen' ;
3036
3137const localClient = createClient ( {
@@ -59,8 +65,12 @@ function App() {
5965 const [ pet , setPet ] = useState < Pet > ( ) ;
6066 const [ petId , setPetId ] = useState < number > ( ) ;
6167 const [ isRequiredNameError , setIsRequiredNameError ] = useState ( false ) ;
68+ const [ showAdvancedExamples , setShowAdvancedExamples ] = useState ( false ) ;
6269
63- // Mutations
70+ // ============================================================================
71+ // Mutations - using the generated mutation options
72+ // ============================================================================
73+ // The mutation options provide the key and fetcher following SWR best practices
6474 const { fetcher : addPetFetcher , key : addPetKey } = addPetMutation ( ) ;
6575 const addPet = useSWRMutation ( addPetKey , addPetFetcher , {
6676 onError : ( error ) => {
@@ -83,7 +93,11 @@ function App() {
8393 } ,
8494 } ) ;
8595
86- // Query - only fetch if petId is set
96+ // ============================================================================
97+ // Pattern 1: Using Options (Recommended for most cases)
98+ // ============================================================================
99+ // The options provide both key and fetcher in the correct format
100+ // Conditional fetching is controlled by passing null to useSWR
87101 const petOptions = petId
88102 ? getPetByIdOptions ( {
89103 client : localClient ,
@@ -98,6 +112,75 @@ function App() {
98112 petOptions ?. fetcher ?? null ,
99113 ) ;
100114
115+ // ============================================================================
116+ // Pattern 2: Using Key function directly (for custom fetchers)
117+ // ============================================================================
118+ // Key functions always return a valid key array, never null
119+ // This gives you full control over the fetcher while maintaining cache consistency
120+ //
121+ // Example (disabled to avoid duplicate requests):
122+ // const petByIdKey = petId ? getPetByIdKey({ path: { petId } }) : null;
123+ // const { data: customFetchedPet } = useSWR(petByIdKey, async (key) => {
124+ // if (!key) return null;
125+ // // Custom fetch logic here - you can add transforms, error handling, etc.
126+ // console.log('Fetching with key:', key);
127+ // const response = await fetch(`/api/pet/${key[1]}`);
128+ // return response.json();
129+ // });
130+
131+ // ============================================================================
132+ // Pattern 3: Optional parameters with optional chaining
133+ // ============================================================================
134+ // When options are optional, keys use optional chaining (options?.query)
135+ // This is safe and always returns a valid key
136+ const inventoryKey = getInventoryKey ( ) ; // No params needed
137+ const { data : inventory } = useSWR (
138+ showAdvancedExamples ? inventoryKey : null ,
139+ async ( ) => {
140+ // Custom fetcher - you control the implementation
141+ const { data } = await getInventory ( {
142+ client : localClient ,
143+ throwOnError : true ,
144+ } ) ;
145+ return data ;
146+ } ,
147+ ) ;
148+
149+ // ============================================================================
150+ // Pattern 4: Required parameters
151+ // ============================================================================
152+ // When parameters are required, options must be provided
153+ // The key function directly accesses options.query without optional chaining
154+ const petsByStatusKey = findPetsByStatusKey ( {
155+ query : { status : 'available' } ,
156+ } ) ;
157+
158+ // Or use the full options for convenience
159+ const { fetcher : petsByStatusFetcher , key : petsByStatusKey2 } =
160+ findPetsByStatusOptions ( {
161+ client : localClient ,
162+ query : { status : 'available' } ,
163+ } ) ;
164+
165+ const { data : availablePets } = useSWR (
166+ showAdvancedExamples ? petsByStatusKey2 : null ,
167+ showAdvancedExamples ? petsByStatusFetcher : null ,
168+ ) ;
169+
170+ // ============================================================================
171+ // Pattern 5: Demonstrating key equality for cache consistency
172+ // ============================================================================
173+ // Keys with the same parameters will have the same cache entry
174+ // This is a core SWR v2 improvement - primitive values in key arrays
175+ const loginKey1 = loginUserKey ( {
176+ query : { password : 'pass' , username : 'test' } ,
177+ } ) ;
178+ const loginKey2 = loginUserKey ( {
179+ query : { password : 'pass' , username : 'test' } ,
180+ } ) ;
181+ // loginKey1 and loginKey2 will be treated as the same cache key by SWR
182+ // because they have the same primitive values: ['/user/login', { username: 'test', password: 'pass' }]
183+
101184 const onAddPet = async ( formData : FormData ) => {
102185 // simple form field validation to demonstrate using schemas
103186 if ( PetSchema . required . includes ( 'name' ) && ! formData . get ( 'name' ) ) {
@@ -180,7 +263,10 @@ function App() {
180263 < Heading > @hey-api/openapi-ts 🤝 SWR</ Heading >
181264 </ Flex >
182265 < Section size = "1" />
266+
267+ { /* Main Demo Section */ }
183268 < Flex direction = "column" gapY = "2" >
269+ < Heading size = "4" > Basic Usage Demo</ Heading >
184270 < Box maxWidth = "240px" >
185271 < Card >
186272 < Flex gap = "3" align = "center" >
@@ -205,6 +291,66 @@ function App() {
205291 < DownloadIcon /> Get Random Pet
206292 </ Button >
207293 </ Flex >
294+
295+ < Section size = "1" />
296+
297+ { /* Advanced Examples Toggle */ }
298+ < Flex direction = "column" gapY = "2" >
299+ < Button
300+ variant = { showAdvancedExamples ? 'solid' : 'outline' }
301+ onClick = { ( ) => setShowAdvancedExamples ( ! showAdvancedExamples ) }
302+ >
303+ { showAdvancedExamples ? 'Hide' : 'Show' } Advanced SWR v2 Examples
304+ </ Button >
305+
306+ { showAdvancedExamples && (
307+ < Card >
308+ < Flex direction = "column" gapY = "2" >
309+ < Heading size = "3" > SWR v2 Key Patterns</ Heading >
310+
311+ < Box >
312+ < Text size = "2" weight = "bold" >
313+ Inventory (Optional params):
314+ </ Text >
315+ < Text size = "1" color = "gray" >
316+ Key: { JSON . stringify ( inventoryKey ) }
317+ </ Text >
318+ < Text size = "1" >
319+ Count:{ ' ' }
320+ { inventory ? Object . keys ( inventory ) . length : 'Loading...' }
321+ </ Text >
322+ </ Box >
323+
324+ < Box >
325+ < Text size = "2" weight = "bold" >
326+ Available Pets (Required params):
327+ </ Text >
328+ < Text size = "1" color = "gray" >
329+ Key: { JSON . stringify ( petsByStatusKey ) }
330+ </ Text >
331+ < Text size = "1" >
332+ Found: { availablePets ?. length ?? 'Loading...' } pets
333+ </ Text >
334+ </ Box >
335+
336+ < Box >
337+ < Text size = "2" weight = "bold" >
338+ Key Equality Demo:
339+ </ Text >
340+ < Text size = "1" color = "gray" >
341+ Key 1: { JSON . stringify ( loginKey1 ) }
342+ </ Text >
343+ < Text size = "1" color = "gray" >
344+ Key 2: { JSON . stringify ( loginKey2 ) }
345+ </ Text >
346+ < Text size = "1" color = "green" >
347+ ✓ These keys are equal and share the same cache
348+ </ Text >
349+ </ Box >
350+ </ Flex >
351+ </ Card >
352+ ) }
353+ </ Flex >
208354 < Section size = "1" />
209355 < Flex direction = "column" gapY = "2" >
210356 < Form . Root
@@ -266,13 +412,24 @@ function App() {
266412 { /*
267413 useSWRInfinite Example (for paginated endpoints):
268414
269- If your OpenAPI spec has pagination configured, you can use useSWRInfinite:
415+ If your OpenAPI spec has pagination configured, the SWR plugin generates
416+ infinite options functions (e.g., findPetsByStatusInfinite).
417+
418+ These functions return an object with:
419+ - getKey: Function that generates keys for each page
420+ - fetcher: Function that fetches a single page
421+
422+ Example usage:
270423
271424 import useSWRInfinite from 'swr/infinite';
272- import { getPetsInfinite } from './client/swr.gen';
425+ import { findPetsByStatusInfinite } from './client/swr.gen';
273426
274427 function InfinitePetList() {
275- const { getKey, fetcher } = getPetsInfinite();
428+ // Get the infinite options with your query parameters
429+ const { getKey, fetcher } = findPetsByStatusInfinite({
430+ query: { status: 'available' }
431+ });
432+
276433 const { data, size, setSize, isLoading } = useSWRInfinite(getKey, fetcher);
277434
278435 const pets = data ? data.flat() : [];
@@ -296,6 +453,9 @@ function App() {
296453 </div>
297454 );
298455 }
456+
457+ Note: The infinite options are only generated for operations that have
458+ pagination configured in the OpenAPI spec.
299459 */ }
300460 </ Container >
301461 </ Box >
0 commit comments