The Rules of Hooks are: 1) Only call hooks at the top level (not inside loops, conditions, or nested functions), 2) Only call hooks from React function components or custom hooks. These rules ensure hooks maintain their state and order between renders.
Custom hooks are functions that use other hooks and must start with 'use' (e.g., useCustomHook). They allow you to extract component logic into reusable functions. Custom hooks can return any values and should follow the Rules of Hooks.
Create custom hooks that encapsulate the shared logic, state, and side effects. Ensure hooks are generic enough for reuse but specific enough to be useful. Consider composition of multiple hooks for complex logic.
Common pitfalls include: missing dependencies leading to stale closures, unnecessary dependencies causing excess renders, object/array dependencies causing infinite loops, and circular dependencies. Use ESLint rules and proper dependency management.
Use useCallback and useRef to create a debounced function that delays execution. Clear previous timeout in cleanup. Consider returning both debounced and immediate execution functions.
Create a custom hook that establishes connection in useEffect, handles message events, and cleans up on unmount. Consider reconnection logic, message queuing, and connection status management.
useRef returns a mutable ref object that persists across renders. Common uses include: accessing DOM elements directly, storing previous values, and holding mutable values that don't trigger re-renders. The .current property can be modified without causing re-renders.
useReducer is preferable for complex state logic involving multiple values or when next state depends on previous state. It follows a Redux-like pattern with actions and reducers, making state transitions more predictable and easier to test.
useDebugValue adds a label to custom hooks in React DevTools. Use it to display custom hook values for debugging. Consider using the format function parameter to defer expensive formatting until the hook is inspected.
Since error boundaries must be class components, create a custom hook that works with an error boundary component. Use try-catch in event handlers and effects. Consider implementing retry logic and error logging.
Use useReducer to manage state history array and current index. Implement actions for undo, redo, and new states. Consider memory usage and limiting history size for large state objects.
Create a custom hook that syncs state with localStorage using useEffect. Handle serialization/deserialization, storage events for cross-tab synchronization, and fallbacks for when storage is unavailable.
useImperativeHandle customizes the instance value exposed to parent components when using ref. It allows you to control which values and methods are accessible via the ref, enabling better encapsulation of component internals.
Use useMemo for expensive calculations and useCallback for function props passed to optimized child components. Ensure dependency arrays are properly configured. Only use when there's a measurable performance benefit to avoid unnecessary complexity.
Define an async function inside useEffect and call it, or use IIFE. Handle cleanup properly for ongoing operations. Consider race conditions and component unmounting. Don't make the useEffect callback itself async.
useLayoutEffect fires synchronously after DOM mutations but before browser paint. Use it when you need to make DOM measurements or mutations that should be synchronized with rendering to prevent visual flickers.
Create a custom hook that manages form state, validation, submission, and error handling using useState or useReducer. Return form state, handlers, and utility methods. Consider validation timing and form reset functionality.
Return cleanup functions from useEffect within custom hooks. Clear timeouts, cancel subscriptions, and remove event listeners. Ensure all resources are properly cleaned up to prevent memory leaks.
Create a custom hook that adds event listeners in useEffect and removes them in cleanup. Consider debouncing or throttling events, and use useCallback for event handlers to maintain referential equality.
Create a custom hook that manages page state, items per page, and total pages using useState. Include methods for page navigation and data fetching. Consider caching results and implementing infinite scroll.
Create custom hooks for data fetching using useState and useEffect. Handle loading, error, and success states. Consider caching, request cancellation, and retry logic. Use libraries like react-query for complex cases.
Create custom hooks for managing auth state, token storage, and user session. Handle login, logout, token refresh, and protected routes. Consider persistent sessions and security implications.
Create custom hooks for validation logic using useState or useReducer. Handle field-level and form-level validation, async validation, and error messages. Consider validation timing and performance.
Create a custom hook that manages keyboard event listeners using useEffect. Handle key combinations, prevent default behaviors, and clean up listeners. Consider focus management and accessibility.
useMemo memoizes a computed value and returns it, while useCallback memoizes a function definition. useMemo is used for expensive calculations, while useCallback is used for function props to prevent unnecessary re-renders of child components.
useContext subscribes to context changes and returns the current context value. It provides a simpler way to consume context compared to Context.Consumer. Components using useContext will re-render when the context value changes.
Create a custom hook that manages scroll position, loading state, and data fetching. Use intersection observer or scroll events. Consider data caching, cleanup, and performance optimization.
Create a custom hook that manages theme state using useState and useContext. Handle theme persistence, dynamic style application, and system preference detection. Consider performance and SSR implications.
Use useReducer with a state machine configuration. Define states, transitions, and actions. Consider using libraries like XState. Handle side effects and state persistence.