Popular Searches
Popular Course Categories
Popular Courses

Rules of Hooks

Rules of Hooks

React Hooks Fundamentals

Rules of Hooks in React JS

The Rules of Hooks are important guidelines that developers must follow when using React Hooks. These rules ensure that React can correctly preserve component state, manage Effects, and maintain predictable behavior between renders. Hooks such as useState(), useEffect(), useContext(), and useRef() must be used in the correct places.

Learn more: JustAcademy React JS Training Course | Register for React JS Course Demo


1. Learning Objectives

  • Understand the meaning and importance of the Rules of Hooks.
  • Learn where Hooks can and cannot be called.
  • Understand why Hooks must be called at the top level.
  • Learn how to use Hooks inside function components and custom Hooks.
  • Identify common Hook errors and understand how to fix them.
  • Understand conditional rendering without breaking Hook rules.
  • Learn how ESLint helps detect Hook-related problems.

2. What Are the Rules of Hooks?

The Rules of Hooks are guidelines that determine where and how React Hooks can be called. React uses the order of Hook calls to associate state and other Hook data with the correct component during rendering.

There are two main rules:

  1. Only call Hooks at the top level.
  2. Only call Hooks from React function components or custom Hooks.

Following these rules helps prevent errors such as incorrect state associations and messages like "Rendered fewer hooks than expected." Read the official Rules of Hooks documentation.


3. Rule One: Only Call Hooks at the Top Level

Hooks must be called at the top level of a function component or custom Hook. Do not call them inside conditions, loops, nested functions, or after a conditional return statement.

Correct Example

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  return (
    <div>
      <h2>Count: {count}</h2>
      <input
        value={name}
        onChange={event => setName(event.target.value)}
        placeholder="Enter your name"
      />
      <button onClick={() => setCount(c => c + 1)}>
        Increase
      </button>
    </div>
  );
}

export default Counter;

Explanation: Both Hooks are called directly inside the component function, before the component returns its JSX. They are called in the same order on every render.

Incorrect Example: Hook Inside a Condition

import { useState } from 'react';

function Example({ isLoggedIn }) {
  if (isLoggedIn) {
    const [name, setName] = useState('');
  }

  return <div>Welcome</div>;
}

Problem: The Hook is called only when isLoggedIn is true. If the condition changes between renders, the order of Hook calls can change.

Corrected Example

import { useState } from 'react';

function Example({ isLoggedIn }) {
  const [name, setName] = useState('');

  if (!isLoggedIn) {
    return <p>Please log in.</p>;
  }

  return <p>Welcome, {name || 'User'}!</p>;
}

Call the Hook before the conditional return so that it runs in the same order on every render.


4. Rule Two: Only Call Hooks from React Functions

Hooks can be called from:

  • React function components.
  • Custom Hooks whose names start with use.

Hooks must not be called directly from ordinary JavaScript functions, class components, event handlers, or functions that run outside React's component or custom Hook rendering process.

Correct Example: Hook in a Function Component

import { useState } from 'react';

function UserProfile() {
  const [username, setUsername] = useState('Alex');

  return <h2>User: {username}</h2>;
}

Incorrect Example: Hook in an Ordinary Function

import { useState } from 'react';

function getUserName() {
  const [name, setName] = useState('Alex');
  return name;
}

Problem: getUserName() is an ordinary JavaScript function, not a React component or custom Hook. Calling a Hook inside it violates the Rules of Hooks.

Corrected Example: Create a Custom Hook

import { useState } from 'react';

function useUserName() {
  const [name, setName] = useState('Alex');

  return { name, setName };
}

function UserProfile() {
  const { name, setName } = useUserName();

  return (
    <div>
      <h2>User: {name}</h2>
      <button onClick={() => setName('Sam')}>
        Change Name
      </button>
    </div>
  );
}

The custom Hook can call other Hooks because it is intended to be called from a React function component or another custom Hook.


5. Never Call Hooks Inside Conditions

Do not place Hooks inside if, else, ternary expressions, or logical expressions such as && and ||. Instead, call the Hook at the top level and put the conditional logic inside the Hook's callback or in the rendered JSX.

Incorrect Example

function UserData({ isLoggedIn }) {
  if (isLoggedIn) {
    useEffect(() => {
      console.log('User is logged in');
    }, []);
  }

  return <div>User Data</div>;
}

Correct Example

import { useEffect } from 'react';

function UserData({ isLoggedIn }) {
  useEffect(() => {
    if (isLoggedIn) {
      console.log('User is logged in');
    }
  }, [isLoggedIn]);

  return <div>User Data</div>;
}

Explanation: The Effect Hook is called on every render. The condition is checked inside the Effect callback instead of determining whether the Hook itself is called.


6. Never Call Hooks Inside Loops

Hooks must not be called inside for, while, or do...while loops. The number of Hook calls could change depending on how many times the loop runs.

Incorrect Example

import { useState } from 'react';

function ProductList() {
  const products = ['Laptop', 'Phone', 'Tablet'];

  for (const product of products) {
    const [selected, setSelected] = useState(false);
  }

  return <div>Products</div>;
}

Correct Approach

Create a separate component for each product and call Hooks at the top level of that component.

import { useState } from 'react';

function ProductItem({ name }) {
  const [selected, setSelected] = useState(false);

  return (
    <button onClick={() => setSelected(value => !value)}>
      {name}: {selected ? 'Selected' : 'Not Selected'}
    </button>
  );
}

function ProductList() {
  const products = ['Laptop', 'Phone', 'Tablet'];

  return (
    <div>
      {products.map(product => (
        <ProductItem key={product} name={product} />
      ))}
    </div>
  );
}

export default ProductList;

Each ProductItem is a separate component with its own state. The parent maps over the product list to render those components.


7. Never Call Hooks Inside Nested Functions or Event Handlers

Event handlers execute in response to user interactions, not as part of the component's normal Hook-calling sequence. Do not call Hooks inside a click handler, form handler, or another nested function.

Incorrect Example

import { useState } from 'react';

function ClickExample() {
  function handleClick() {
    const [count, setCount] = useState(0);
  }

  return <button onClick={handleClick}>Click</button>;
}

Correct Example

import { useState } from 'react';

function ClickExample() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(previousCount => previousCount + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

export default ClickExample;

The Hook is declared at the top level. The event handler updates state using the setter function.


8. Do Not Call Hooks After a Conditional Return

Hooks should appear before any early return that may cause them to be skipped on some renders.

Incorrect Example

import { useState } from 'react';

function Profile({ user }) {
  if (!user) {
    return <p>No user found</p>;
  }

  const [expanded, setExpanded] = useState(false);

  return <div>Profile</div>;
}

Correct Example

import { useState } from 'react';

function Profile({ user }) {
  const [expanded, setExpanded] = useState(false);

  if (!user) {
    return <p>No user found</p>;
  }

  return (
    <div>
      <p>Profile</p>
      <button onClick={() => setExpanded(value => !value)}>
        {expanded ? 'Hide Details' : 'Show Details'}
      </button>
    </div>
  );
}

Even if the component returns early, the Hook is still called before that return.


9. Do Not Call Hooks Inside useEffect, useMemo, or Other Hook Callbacks

Although custom Hooks can call other Hooks, do not call a Hook inside a callback passed to another Hook. The nested callback is not the top-level body of a component or custom Hook.

Incorrect Example

import { useEffect, useState } from 'react';

function Example() {
  useEffect(() => {
    const [count, setCount] = useState(0);
  }, []);

  return <div>Example</div>;
}

Correct Example

import { useEffect, useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);

  return (
    <button onClick={() => setCount(value => value + 1)}>
      Count: {count}
    </button>
  );
}

Call useState() at the component's top level, then use its value inside the Effect when needed.


10. Do Not Call Hooks Inside try, catch, or finally Blocks

Hooks should not be placed inside exception-handling blocks because the execution path may change between renders.

Incorrect Example

import { useState } from 'react';

function Example() {
  try {
    const [value, setValue] = useState('');
  } catch (error) {
    console.error(error);
  }

  return <div>Example</div>;
}

Correct Example

import { useState } from 'react';

function Example() {
  const [value, setValue] = useState('');

  function handleAction() {
    try {
      console.log('Current value:', value);
    } catch (error) {
      console.error(error);
    }
  }

  return (
    <button onClick={handleAction}>
      Run Action
    </button>
  );
}

The Hook is called at the top level, while ordinary JavaScript exception handling is performed inside the event handler.


11. Why Must Hooks Be Called in the Same Order?

React associates Hook state with the order of Hook calls in a component. If Hooks are conditionally skipped or called in a different order, React may associate state with the wrong Hook call or detect an inconsistent number of Hooks.

Example of the Problem

function Example({ showName }) {
  const [count, setCount] = useState(0);

  if (showName) {
    const [name, setName] = useState('');
  }

  const [active, setActive] = useState(true);

  return <div>Example</div>;
}

When showName changes, the number and order of Hook calls can change. This can cause a Hook-order error.

How to Fix It

function Example({ showName }) {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');
  const [active, setActive] = useState(true);

  return (
    <div>
      <p>Count: {count}</p>
      {showName && <p>Name: {name}</p>}
      <p>Active: {active ? 'Yes' : 'No'}</p>
    </div>
  );
}

All Hooks are called consistently. Conditional rendering controls what appears on the screen, not whether the Hooks are called.


12. Special Note About the React use API

React's use() API is a special case and is different from ordinary Hooks such as useState() and useEffect(). In supported React versions, use() can be called conditionally or inside loops, but it must still be used inside a component or custom Hook and cannot be wrapped in try/catch.

For beginners, follow the standard top-level rule for ordinary Hooks unless you are specifically learning the use() API. Read the official use API documentation.


13. Common Errors Related to the Rules of Hooks

Error or Problem Possible Cause Solution
Invalid hook call A Hook is called outside a function component or custom Hook, or there is a React installation/version issue. Check where Hooks are called and verify React and React DOM versions and package installations.
Rendered fewer hooks than expected A Hook was skipped because of a conditional return or branch. Move ordinary Hooks to the top level before early returns.
Rendered more hooks than during the previous render A Hook was called conditionally or in a loop. Keep Hook calls in a consistent order.
Hook called inside a callback A Hook is called inside an event handler or another Hook's callback. Move the Hook to the component or custom Hook's top level.
Effect dependency warning A dependency used by an Effect is missing from its dependency array. Review the Effect and include the necessary reactive dependencies.

An invalid Hook call can also result from mismatched React and React DOM versions or multiple copies of React in the same application. If the Hook placement is correct, check the project's dependencies. Read the official troubleshooting guide.


14. Using ESLint to Check Hook Rules

ESLint can detect many violations of the Rules of Hooks and warn about missing dependencies in Effects. The official React Hooks ESLint plugin provides rules such as rules-of-hooks and exhaustive-deps.

Install the Plugin

npm install --save-dev eslint-plugin-react-hooks

Configure the plugin according to your ESLint setup and use its recommended rules. Modern React projects may already include this plugin or related configuration.

Example ESLint Configuration Concept

{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

This is a simplified example of the rule settings. The exact configuration depends on your ESLint version and project setup. Use the official guide: React Hooks ESLint Plugin.


15. Best Practices for Using Hooks

  • Call ordinary Hooks at the top level of components and custom Hooks.
  • Never call Hooks conditionally or inside loops.
  • Place Hooks before conditional returns.
  • Use custom Hooks to reuse stateful logic across components.
  • Use clear names beginning with use for custom Hooks.
  • Do not call Hooks directly from event handlers or ordinary utility functions.
  • Do not call Hooks inside callbacks passed to useEffect(), useMemo(), or other Hooks.
  • Follow Effect dependency warnings and avoid suppressing them without understanding the reason.
  • Use ESLint to detect common Hook mistakes during development.
  • Keep components and Hooks pure during rendering; perform side effects in the appropriate event handlers or Effects.

16. Mini Project: Login Form Following the Rules of Hooks

Objective: Create a simple login form that follows the Rules of Hooks. The component stores email and password values at the top level, validates the fields when the user submits, and displays a message.

Complete Code

import { useState } from 'react';

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [message, setMessage] = useState('');

  function handleSubmit(event) {
    event.preventDefault();

    if (!email.trim() || !password.trim()) {
      setMessage('Please enter both email and password.');
      return;
    }

    setMessage('Form validation passed.');
  }

  return (
    <form onSubmit={handleSubmit}>
      <h2>Login Form</h2>

      <label htmlFor="email">Email</label>
      <input
        id="email"
        type="email"
        value={email}
        onChange={event => setEmail(event.target.value)}
        required
      />

      <label htmlFor="password">Password</label>
      <input
        id="password"
        type="password"
        value={password}
        onChange={event => setPassword(event.target.value)}
        required
      />

      <button type="submit">Submit</button>
      <p role="status">{message}</p>
    </form>
  );
}

export default LoginForm;

Rules Demonstrated

  • All three useState() calls are at the top level.
  • No Hooks are called inside the form submit handler.
  • The handler uses state setters to update the message.
  • Conditional validation occurs inside the event handler without changing Hook order.

Note: This project demonstrates client-side form behavior, not authentication. A production login must use a secure authentication service and server-side validation.


17. Interview Questions and Answers

Q1. What are the Rules of Hooks?

The main rules are to call ordinary Hooks at the top level and to call them only from React function components or custom Hooks.

Q2. Why should Hooks not be called inside conditions?

Conditional calls can change the order of Hook calls between renders, causing React to associate state incorrectly or report a Hook-order error.

Q3. Can Hooks be called inside event handlers?

No. Event handlers should use existing state and setter functions. They must not call Hooks.

Q4. Can Hooks be called inside custom Hooks?

Yes. Custom Hooks are specifically designed to call other Hooks and reuse stateful logic.

Q5. Can Hooks be used inside class components?

No. Hooks are designed for function components and custom Hooks, not class components.

Q6. Why must Hooks be called before an early return?

This helps ensure that ordinary Hooks are called in the same order on every render, regardless of the returned UI.

Q7. How can developers detect violations of the Rules of Hooks?

The official React Hooks ESLint plugin can detect many violations and warn about dependency issues.

Q8. Can a Hook be called inside useEffect()?

No. The callback passed to useEffect() is not a valid place to call another Hook. Call the Hook at the top level and use its returned values inside the Effect.

Q9. What is a custom Hook?

A custom Hook is a reusable JavaScript function whose name starts with use and that may call other Hooks.

Q10. What should you do if you get an invalid Hook call error?

Check Hook placement first. Also verify that React and React DOM versions are compatible and that the application does not unintentionally load multiple copies of React.


18. Practice Exercises

  1. Create a counter using useState() and ensure the Hook is called at the top level.
  2. Build a login form with email and password state.
  3. Write a component that conditionally displays a message without conditionally calling Hooks.
  4. Create a custom Hook named useToggle() to manage a Boolean value.
  5. Build a product list using a separate component for each product.
  6. Use useEffect() to update the browser title when state changes.
  7. Fix a component that calls a Hook after an early return.
  8. Install or configure the React Hooks ESLint plugin in a practice project.
  9. Identify and correct Hook calls inside loops and event handlers.
  10. Build a small profile component that follows both main Rules of Hooks.

19. Revision Checklist

  • Understand the two main Rules of Hooks.
  • Call ordinary Hooks only at the top level.
  • Call Hooks only from function components or custom Hooks.
  • Avoid Hook calls inside conditions, loops, and nested callbacks.
  • Place Hooks before early return statements.
  • Use state setters instead of calling Hooks inside event handlers.
  • Understand why Hook call order matters.
  • Recognize common invalid Hook call errors.
  • Use ESLint to help enforce the rules.
  • Practice writing components and custom Hooks correctly.

20. Additional Learning Resources


Conclusion

The Rules of Hooks help React manage state and other Hook behavior reliably across renders. Always call ordinary Hooks at the top level of function components or custom Hooks, keep their call order consistent, and use conditional logic inside the component or Hook rather than around the Hook call. Following these rules and using ESLint will help you write more predictable and maintainable React applications.

Explore the JustAcademy React JS Training Course or register for a React JS course demo.

whatsapp