initial commit
This commit is contained in:
267
templates/hook.template.ts
Normal file
267
templates/hook.template.ts
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* Custom Hook Template
|
||||
*
|
||||
* Usage: Copy this file to create new custom hooks
|
||||
* 1. Replace TEMPLATE_NAME with your hook name (use camelCase)
|
||||
* 2. Define the hook parameters and return type
|
||||
* 3. Implement your hook logic
|
||||
*/
|
||||
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
|
||||
// Hook parameters interface
|
||||
interface UseTemplateHookParams {
|
||||
// Define your parameters here
|
||||
initialValue?: string
|
||||
autoFetch?: boolean
|
||||
onSuccess?: (data: any) => void
|
||||
onError?: (error: Error) => void
|
||||
debounceMs?: number
|
||||
}
|
||||
|
||||
// Hook return type
|
||||
interface UseTemplateHookReturn {
|
||||
// Define what your hook returns
|
||||
data: any
|
||||
isLoading: boolean
|
||||
error: Error | null
|
||||
refetch: () => void
|
||||
mutate: (data: any) => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook template
|
||||
*
|
||||
* @param params - Hook parameters
|
||||
* @returns Hook state and functions
|
||||
*/
|
||||
export function useTemplateHook({
|
||||
initialValue = '',
|
||||
autoFetch = true,
|
||||
onSuccess,
|
||||
onError,
|
||||
debounceMs = 300,
|
||||
}: UseTemplateHookParams = {}): UseTemplateHookReturn {
|
||||
// Local state
|
||||
const [data, setData] = useState<any>(initialValue)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
|
||||
// Refs for cleanup and debouncing
|
||||
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
// Query for fetching data
|
||||
const query = useQuery({
|
||||
queryKey: ['template-hook', initialValue],
|
||||
queryFn: async () => {
|
||||
// Implement your data fetching logic
|
||||
const response = await fetch('/api/template-endpoint', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
|
||||
return response.json()
|
||||
},
|
||||
enabled: autoFetch,
|
||||
})
|
||||
|
||||
// Handle query success/error with useEffect
|
||||
useEffect(() => {
|
||||
if (query.data && !query.isLoading && !query.error) {
|
||||
setData(query.data)
|
||||
onSuccess?.(query.data)
|
||||
}
|
||||
}, [query.data, query.isLoading, query.error, onSuccess])
|
||||
|
||||
useEffect(() => {
|
||||
if (query.error) {
|
||||
setError(query.error)
|
||||
onError?.(query.error)
|
||||
}
|
||||
}, [query.error, onError])
|
||||
|
||||
// Mutation for updating data
|
||||
const mutation = useMutation({
|
||||
mutationFn: async (newData: any) => {
|
||||
const response = await fetch('/api/template-endpoint', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(newData),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
|
||||
return response.json()
|
||||
},
|
||||
})
|
||||
|
||||
// Handle mutation success/error with useEffect
|
||||
useEffect(() => {
|
||||
if (mutation.data && mutation.isSuccess) {
|
||||
// Update cache
|
||||
queryClient.setQueryData(['template-hook', initialValue], mutation.data)
|
||||
setData(mutation.data)
|
||||
onSuccess?.(mutation.data)
|
||||
}
|
||||
}, [mutation.data, mutation.isSuccess, queryClient, initialValue, onSuccess])
|
||||
|
||||
useEffect(() => {
|
||||
if (mutation.error) {
|
||||
setError(mutation.error)
|
||||
onError?.(mutation.error)
|
||||
}
|
||||
}, [mutation.error, onError])
|
||||
|
||||
// Debounced function
|
||||
const debouncedFunction = useCallback(
|
||||
(value: any) => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
}
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
// Implement debounced logic here
|
||||
console.log('Debounced value:', value)
|
||||
}, debounceMs)
|
||||
},
|
||||
[debounceMs]
|
||||
)
|
||||
|
||||
// Effect for cleanup
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Refetch function
|
||||
const refetch = useCallback(() => {
|
||||
query.refetch()
|
||||
}, [query])
|
||||
|
||||
// Mutate function
|
||||
const mutate = useCallback(
|
||||
(newData: any) => {
|
||||
mutation.mutate(newData)
|
||||
},
|
||||
[mutation]
|
||||
)
|
||||
|
||||
// Reset function
|
||||
const reset = useCallback(() => {
|
||||
setData(initialValue)
|
||||
setError(null)
|
||||
queryClient.removeQueries({ queryKey: ['template-hook', initialValue] })
|
||||
}, [initialValue, queryClient])
|
||||
|
||||
return {
|
||||
data: query.data || data,
|
||||
isLoading: query.isLoading || mutation.isPending,
|
||||
error: query.error || mutation.error || error,
|
||||
refetch,
|
||||
mutate,
|
||||
reset,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative hook patterns:
|
||||
*
|
||||
* 1. Simple State Hook:
|
||||
*
|
||||
* export function useSimpleState<T>(initialValue: T) {
|
||||
* const [value, setValue] = useState<T>(initialValue);
|
||||
*
|
||||
* const reset = useCallback(() => setValue(initialValue), [initialValue]);
|
||||
*
|
||||
* return [value, setValue, reset] as const;
|
||||
* }
|
||||
*
|
||||
* 2. Local Storage Hook:
|
||||
*
|
||||
* export function useLocalStorage<T>(key: string, initialValue: T) {
|
||||
* const [storedValue, setStoredValue] = useState<T>(() => {
|
||||
* try {
|
||||
* const item = window.localStorage.getItem(key);
|
||||
* return item ? JSON.parse(item) : initialValue;
|
||||
* } catch (error) {
|
||||
* return initialValue;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* const setValue = (value: T | ((val: T) => T)) => {
|
||||
* try {
|
||||
* const valueToStore = value instanceof Function ? value(storedValue) : value;
|
||||
* setStoredValue(valueToStore);
|
||||
* window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||
* } catch (error) {
|
||||
* console.error('Error saving to localStorage:', error);
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* return [storedValue, setValue] as const;
|
||||
* }
|
||||
*
|
||||
* 3. API Hook with SWR pattern:
|
||||
*
|
||||
* export function useApi<T>(url: string, options?: RequestInit) {
|
||||
* const [data, setData] = useState<T | null>(null);
|
||||
* const [loading, setLoading] = useState(true);
|
||||
* const [error, setError] = useState<Error | null>(null);
|
||||
*
|
||||
* useEffect(() => {
|
||||
* let cancelled = false;
|
||||
*
|
||||
* const fetchData = async () => {
|
||||
* try {
|
||||
* setLoading(true);
|
||||
* const response = await fetch(url, options);
|
||||
*
|
||||
* if (!response.ok) {
|
||||
* throw new Error(`HTTP error! status: ${response.status}`);
|
||||
* }
|
||||
*
|
||||
* const result = await response.json();
|
||||
*
|
||||
* if (!cancelled) {
|
||||
* setData(result);
|
||||
* setError(null);
|
||||
* }
|
||||
* } catch (err) {
|
||||
* if (!cancelled) {
|
||||
* setError(err instanceof Error ? err : new Error('Unknown error'));
|
||||
* }
|
||||
* } finally {
|
||||
* if (!cancelled) {
|
||||
* setLoading(false);
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* fetchData();
|
||||
*
|
||||
* return () => {
|
||||
* cancelled = true;
|
||||
* };
|
||||
* }, [url]);
|
||||
*
|
||||
* return { data, loading, error };
|
||||
* }
|
||||
*/
|
||||
Reference in New Issue
Block a user