DEV Community

Abhay Singh Kathayat
Abhay Singh Kathayat

Posted on

The Essential Rules of Hooks in React: How to Use Hooks Properly

Rules of Hooks in React

React hooks are a powerful feature that allow you to use state and other React features in functional components. However, to ensure that hooks work properly and consistently, there are specific rules you must follow when using them. These rules help React manage hooks' state, effects, and other features in an optimized and predictable way.

The Rules of Hooks are:

  1. Only call hooks at the top level:
    • Do not call hooks inside loops, conditions, or nested functions. Hooks should always be called at the top level of your React component or custom hook.
    • This ensures that hooks are called in the same order on every render, which is critical for React’s state management and rendering logic.

Bad Example:

   if (someCondition) {
     useState(0);  // Bad: Hook inside condition
   }
Enter fullscreen mode Exit fullscreen mode

Good Example:

   const [count, setCount] = useState(0); // Always called at the top level
Enter fullscreen mode Exit fullscreen mode
  1. Only call hooks from React functions:
    • Call hooks from functional components or custom hooks. Do not call them from regular JavaScript functions, class components, or outside React’s functional component ecosystem.
    • Hooks are designed to work only with functional components or custom hooks, not in regular functions or class methods.

Bad Example:

   function regularFunction() {
     useState(0);  // Bad: Hook used outside a React component
   }
Enter fullscreen mode Exit fullscreen mode

Good Example:

   const MyComponent = () => {
     const [count, setCount] = useState(0); // Good: Inside a functional component
   };
Enter fullscreen mode Exit fullscreen mode
  1. Use the use prefix for custom hooks:
    • Custom hooks must start with use to follow React’s convention and to differentiate them from regular functions.
    • This helps with readability and consistency, and React can internally check for violations of rules when it sees a function with the use prefix.

Bad Example:

   function fetchData() {  // Bad: Not prefixed with "use"
     // Custom hook logic
   }
Enter fullscreen mode Exit fullscreen mode

Good Example:

   function useFetchData() {  // Good: Prefixed with "use"
     // Custom hook logic
   }
Enter fullscreen mode Exit fullscreen mode

Why Are These Rules Important?

  • Order of Hook Calls: Hooks rely on the order in which they are called. React internally tracks which hook corresponds to which state or effect, so if you call hooks conditionally or inside loops, their order can change between renders. This leads to unexpected behavior and bugs. By calling hooks at the top level, React can always track them in a consistent manner.

  • Consistency Across Renders: React depends on hooks being called in the same order each time a component re-renders. If hooks are called in a different order during different renders, React won’t know how to apply the state and effects correctly.

  • Avoiding Hook Call Mismatches: Calling hooks in non-React functions or in conditional blocks would result in mismatches and errors because React won’t know which state corresponds to which hook.


How to Follow the Rules Effectively

  1. Place all hooks at the top level of the component: This includes useState, useEffect, useCallback, useMemo, and other React hooks. Never place them inside loops, conditions, or nested functions.

Example:

   const MyComponent = () => {
     const [count, setCount] = useState(0);  // Always call hooks at the top level
     const [name, setName] = useState("");

     const handleClick = () => {
       setCount(count + 1);  // Handle events and logic inside functions
     };

     return (
       <div>
         <p>Count: {count}</p>
         <p>Name: {name}</p>
         <button onClick={handleClick}>Increment</button>
       </div>
     );
   };
Enter fullscreen mode Exit fullscreen mode
  1. Create custom hooks for reusable logic: If you find that you are reusing the same logic in multiple components, you can create custom hooks. Always start the custom hook name with use to ensure consistency and avoid confusion with regular functions.

Example:

   const useCounter = (initialValue) => {
     const [count, setCount] = useState(initialValue);

     const increment = () => {
       setCount(count + 1);
     };

     return { count, increment };
   };

   const CounterComponent = () => {
     const { count, increment } = useCounter(0);  // Use the custom hook
     return (
       <div>
         <p>Count: {count}</p>
         <button onClick={increment}>Increment</button>
       </div>
     );
   };
Enter fullscreen mode Exit fullscreen mode
  1. Use hooks in the same order on every render: Even if you use hooks inside loops or conditionals, make sure that hooks are called in the same order during every render.

Bad Example:

   const MyComponent = ({ isUserLoggedIn }) => {
     if (isUserLoggedIn) {
       const [userData, setUserData] = useState(null);  // Hook inside condition
     }

     return <div>Welcome to my app!</div>;
   };
Enter fullscreen mode Exit fullscreen mode

Good Example:

   const MyComponent = ({ isUserLoggedIn }) => {
     const [userData, setUserData] = useState(null); // Always at the top level

     if (isUserLoggedIn) {
       // Additional logic here
     }

     return <div>Welcome to my app!</div>;
   };
Enter fullscreen mode Exit fullscreen mode
  1. Follow the rules for custom hooks: Custom hooks are great for sharing reusable logic across components. Always prefix them with use and ensure they follow the same rules as React’s built-in hooks.

Example:

   function useLocalStorage(key, initialValue) {
     const [storedValue, setStoredValue] = useState(() => {
       try {
         const item = window.localStorage.getItem(key);
         return item ? JSON.parse(item) : initialValue;
       } catch (error) {
         return initialValue;
       }
     });

     const setValue = (value) => {
       try {
         setStoredValue(value);
         window.localStorage.setItem(key, JSON.stringify(value));
       } catch (error) {
         console.error("Error setting localStorage", error);
       }
     };

     return [storedValue, setValue];
   }
Enter fullscreen mode Exit fullscreen mode

Common Mistakes to Avoid

  • Calling hooks conditionally: You may be tempted to call hooks inside conditions or loops, but this violates the rule that hooks must always be called in the same order. Instead, consider restructuring your code to always call hooks in the same order.

  • Using hooks outside of React components or custom hooks: React hooks can only be used inside functional components or custom hooks. Using hooks inside class components or regular functions will lead to errors.


Conclusion

The Rules of Hooks are fundamental principles that allow React to maintain a consistent and predictable state management system. By adhering to these rules, React can ensure that your components work properly, the state is correctly managed, and side effects are executed as expected. Always remember:

  • Call hooks at the top level of your components.
  • Only call hooks from React functions or custom hooks.
  • Always start custom hook names with use.

Following these guidelines ensures your React application is both performant and bug-free.


Top comments (0)