Created
April 17, 2025 20:35
-
-
Save fmartins-andre/a7117c56da1eb631d48ad470ac0a131e to your computer and use it in GitHub Desktop.
Factory function to create tanstack react lazy query hooks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* execute a callback and return an result/error array | |
* | |
* @param {callback} function to be executed | |
*/ | |
export const safePromise = async <TData, TError>( | |
callback: () => Promise<TData> | |
): Promise<[false, TError, undefined] | [true, undefined, TData]> => { | |
try { | |
const response: TData = await callback() | |
return [true, undefined, response] | |
} catch (error) { | |
return [false, error as TError, undefined] | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
DefaultError, | |
UseBaseQueryOptions, | |
useQueryClient, | |
} from '@tanstack/react-query' | |
import { useCallback, useState } from 'react' | |
import { safePromise } from './safe-promise' | |
type LazyQueryState<TParams> = { | |
isFetching: boolean | |
params: TParams | undefined | |
} | |
export type LazyQueryOptions<TParams, TData, TError = unknown> = { | |
onQuery?: (params: TParams, cachedData: TData | undefined) => void | |
onSuccess?: (params: TParams, data: TData) => void | |
onError?: (params: TParams, error: TError) => void | |
onSettled?: ( | |
params: TParams, | |
error: TError | undefined, | |
data: TData | undefined | |
) => void | |
} | |
export type LazyQueryHook<TParams, TData, TError = unknown> = ( | |
options?: LazyQueryOptions<TParams, TData, TError> | |
) => [ | |
/** | |
* Trigger function: invokes the query with params and returns the result | |
*/ | |
(params: TParams) => Promise<TData>, | |
/** | |
* Query state: includes data, status flags, error, etc. | |
*/ | |
{ | |
data: TData | undefined | |
isFetching: boolean | |
isLoading: boolean | |
}, | |
] | |
/** | |
* createLazyQueryHook | |
* @param clientOptions - A function that returns query options for the given parameters | |
*/ | |
export function createLazyQueryHook<TParams, TData, TError = DefaultError>( | |
clientOptions: ( | |
params: TParams | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
) => UseBaseQueryOptions<any, TError, TData, any, any> | |
): LazyQueryHook<TParams, TData, TError> { | |
try { | |
return (options?: LazyQueryOptions<TParams, TData, TError>) => { | |
const queryClient = useQueryClient() | |
const [state, setState] = useState<LazyQueryState<TParams>>({ | |
isFetching: false, | |
params: undefined, | |
}) | |
const queryOpts = clientOptions( | |
state.params ?? ({} as unknown as TParams) | |
) | |
const data = queryClient.getQueryData<TData>(queryOpts.queryKey) | |
const trigger = useCallback( | |
async (params: TParams) => { | |
try { | |
setState({ isFetching: true, params }) | |
options?.onQuery?.(params, data) | |
const queryOpts = clientOptions(params) | |
const [ok, error, result] = await safePromise<TData, TError>( | |
() => queryClient.fetchQuery(queryOpts) as Promise<TData> | |
) | |
setState((prev) => ({ ...prev, isFetching: false })) | |
options?.onSettled?.(params, error, result) | |
if (!ok) { | |
options?.onError?.(params, error) | |
throw error | |
} | |
options?.onSuccess?.(params, result) | |
return result | |
} catch (error) { | |
console.error( | |
'Error in lazy query trigger function. Please check the parameters and types.', | |
error | |
) | |
throw error | |
} | |
}, | |
[queryClient, options, data] | |
) | |
return [ | |
trigger, | |
{ | |
data, | |
isFetching: state.isFetching, | |
isLoading: state.isFetching && !data, | |
}, | |
] | |
} | |
} catch (error) { | |
console.error( | |
'Error creating lazy query hook. Please check the parameters and types.', | |
error | |
) | |
throw error | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment