Naming conventions for React hooks
The fundamental rule: every custom hook must start with 'use'. This isn't stylistic preference: React depends on this convention to apply the Rules of Hooks correctly. React's linter detects hooks by the 'use' prefix and validates they aren't called conditionally or inside loops.
Names should be descriptive yet concise. useFetch is better than useData (vague) or useFetchDataFromApiEndpoint (verbose). If your hook manages boolean state, consider useToggle, useBoolean, or useSwitch. For side effects, use verbs: useDebounce, useThrottle, useInterval.
Avoid names that collide with React native hooks or popular libraries. Don't name your custom hooks useState or useEffect. If your hook extends native functionality, add a descriptive prefix: useLocalStorageState combines useState with localStorage.
Hook composition patterns
Derived state hooks: When a hook computes values from others, use 'use' + derived noun. useFilteredList, useSearchResults, useSortedData. These hooks encapsulate transformation and memoization logic.
Synchronization hooks: For side effects that sync with external systems, reflect the action. useSyncWithLocalStorage, useSubscribeToWebSocket, usePersistForm. The verb indicates side effect presence.
Aggregation hooks: When combining multiple hooks into a high-level one, the name should reflect the complete domain. useAuthenticatedUser might internally use useAuth, useProfile, and usePermissions. Document internal dependencies.
Configuration hooks: If your hook accepts complex options, consider the useX + useXConfig pattern. For example, useForm with useFormConfig for custom validators.
Common mistakes when naming hooks
Overly generic names: useData or useHandler say nothing. What data? What does it handle? Be specific: useUserProfile, useClickHandler. In a project with 30 hooks, generic names create confusion.
Cryptic abbreviations: useFetchUsr, useQryRes. Vowels are free, don't omit them. The only acceptable exceptions are standard domain abbreviations: useAPI, useURL, useHTTP.
Mixed responsibilities: useFetchAndValidateAndStore indicates the hook does too much. Split it into useFetch, useValidation, and useStorage. Then create useUserWorkflow that combines them if you need a high-level abstraction.
Not indicating async: If your hook returns promises, consider suffixes like useAsyncData, useFetchAsync. While not mandatory, it helps consumers anticipate loading/error state handling.
Organizing hooks in large projects
Create a directory structure by category: hooks/state/, hooks/api/, hooks/ui/, hooks/forms/. Each hook lives in its own file with tests alongside: useDebounce.ts + useDebounce.test.ts.
Export hooks from a central index for clean imports: import { useAuth, useUser } from '@/hooks' instead of long relative paths. Use barrel exports but avoid forcing full bundle recompilation when one hook changes.
File naming: The file should match the main hook it exports. If useForm.ts also exports useField and useValidation, document this in the file's JSDoc comment.
Domain hooks: Group hooks related to specific features. In features/cart/hooks/ you have useCart, useCartItems, useCheckout. This scales better than cramming everything into a global hooks/ directory with 100 files.