Instruction file imported from joshcristopher/Lovable.Boilerplate (
.cursor/rules/hooks.mdc). Copyright stays with the author.
Custom Hooks Rules
Hook Organization Patterns
Data Fetching Hooks
// hooks/useUsers.ts
export const useUsers = () => {
return useQuery({
queryKey: ['users'],
queryFn: () => userService.getAllUsers(),
staleTime: 5 * 60 * 1000, // 5 minutes
})
}
export const useUser = (id: string) => {
return useQuery({
queryKey: ['users', id],
queryFn: () => userService.getUser(id),
enabled: !!id,
})
}
Form Hooks
// hooks/useUserForm.ts
export const useUserForm = (initialData?: Partial<User>) => {
const form = useForm<UserFormData>({
resolver: zodResolver(userSchema),
defaultValues: initialData || {},
})
const { mutate: saveUser, isPending } = useMutation({
mutationFn: userService.updateUser,
onSuccess: () => toast.success('User saved'),
onError: (error) => toast.error(error.message),
})
return { form, saveUser, isPending }
}
UI State Hooks
// hooks/useDisclosure.ts
export const useDisclosure = (initialState = false) => {
const [isOpen, setIsOpen] = useState(initialState)
const open = useCallback(() => setIsOpen(true), [])
const close = useCallback(() => setIsOpen(false), [])
const toggle = useCallback(() => setIsOpen(prev => !prev), [])
return { isOpen, open, close, toggle }
}
Local Storage Hook
// hooks/useLocalStorage.ts
export const 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 = useCallback((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)
}
}, [key, storedValue])
return [storedValue, setValue] as const
}
Hook Naming Conventions
- Data:
useUsers,useUser,useProducts - Forms:
useUserForm,useProductForm - UI State:
useDisclosure,useToggle,useLocalStorage - Business Logic:
useAuth,useCart,useNotifications
Hook Extraction Rules
Extract Logic When:
- Same logic used in 2+ components
- Component exceeds 100 lines due to logic
- Complex state management patterns
- API interaction patterns
Don't Extract When:
- Logic is component-specific
- Only used once
- Simple useState patterns