ai-wpa/templates/hook.template.ts

268 lines
6.6 KiB
TypeScript

/**
* 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 };
* }
*/