React Hooks have revolutionized the way we write functional components in React, providing a concise and powerful way to manage state and side effects.

However, as with any new feature, it comes with its own set of rules and guidelines. One common error that React developers may encounter is the “react hooks must be called in a react function component or a custom react hook function” error.

In this article, we will delve into the details of this error, understand why it occurs, and provide best practices for fixing it.

What Causes the “React Hooks Must Be Called In a React Function Component or a Custom React Hook Function” Error

There are rules involved with using React Hooks. Many React developers jump these rules when learning React, which leads to errors. One of these errors is “react hooks must be called in a react function component or a custom react hook function”.

This error occurs when two major things happen:

  • Using React Hooks in class components
  • Calling React Hooks within a nested function

React Hooks, such as useState, useEffect, and useContext, are designed to be called at the top level of a functional component or a custom hook function. They should also only be called in functional components and not class components. These are two major rules of React Hooks, which ensure that Hooks are used correctly and consistently in React components.

When Hooks are called in invalid places, you get this error: “react hooks must be called in a react function component or a custom react hook function”. This ESLint error exists as a safeguard to prevent Hooks from being used in ways that can cause unexpected behavior and bugs in your React application.

2 Ways To Fix the “React Hooks Must Be Called In a React Function Component or a Custom React Hook Function” Error

This error can be fixed in a few ways depending on the situation or how you have misused the React Hook.

1. Never Call React Hooks in Class Components

Hooks are designed to work with functional components or custom hooks only — because they use the call stack of the functional components to manage the state and lifecycle of the component. Class components do not have this call stack, so you cannot use Hooks directly in them.

import React, { useState } from 'react';
class Counter extends React.Component {
    state = { count: 0 };
    render() {
        const [count, setCount] = useState(0);
        // Error: React Hooks must be called in a React function component or a custom React Hook function
        return (
            <div>
                <p>You clicked {count} times</p>
                <button onClick={() => setCount(count + 1)}>Click me</button>
            </div>
        );
    }
}
export default Counter;

If you do, you’ll get this error:

React function error
Error

However, there are a few ways to fix this, depending on your preference. You can decide to use state and setState with class components, convert the component to a functional component, or use a Higher-Order Component (HOC).

A. Convert the Class Component to a Functional Component

The only way Hooks can work is when you are using a functional component. This is because Hooks are designed to work with functional components.

In the example below, the previous class component is converted to a functional component:

import { useState } from 'react';

function MyComponent(props) {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

B. Use a Higher-Order Component (HOC)

One way to use Hooks in a class component is to use a Higher-Order Component (HOC).

HOC is a function that takes a component and returns a new component with additional props or functionality. Here’s an example of how to use a HOC to provide Hooks to a class component:

import React, { useState } from 'react';

function withHooks(WrappedComponent) {
  return function(props) {
    const [count, setCount] = useState(0);
    return (
      < WrappedComponent count={count} setCount={setCount} {...props} />
    );
  };
}

class MyComponent extends React.Component {
  render() {
    const { count, setCount } = this.props;
    return (
      < div>
        < p>Count: {count}< /p>
        < button onClick={() => setCount(count + 1)}>Increment< /button>
      < /div>
    );
  }
}

export default withHooks(MyComponent);

C. Use States in Class Component

Finally, suppose you don’t want to change your component’s syntax. You can decide to use state and setState instead of useState Hook:

import React from 'react';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleIncrement = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleIncrement}>Increment</button>
      </div>
    );
  }
}

export default MyComponent;

2. Never Call React Hooks Within a Nested Function

One clear rule of React Hooks is that all Hooks should be called at the top level of a functional component or a custom hook function. When you call a Hook within a nested function, you’ve fouled the rule.

In the example below, the useState Hook is called in the handleClick function:

import React, { useState } from 'react';
function MyComponent() {
    let count = 0;
    function handleClick() {
        const [count, setCount] = useState(0);
        setCount(count + 1);
    }
    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={handleClick}>Increment</button>
        </div>
    );
}

export default MyComponent;

This will throw the following error:

Another React error
Error example

You can fix this by moving the Hook outside the function — to the top level of your functional component:

import React, { useState } from 'react';

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

    function handleClick() {
        setCount(count + 1);
    }

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={handleClick}>Increment</button>
        </div>
    );
}

export default MyComponent;

Summary

In this article, you have learned what causes the “react hooks must be called in a react function component or a custom react hook function” error, and how it can be fixed.

Always follow the rules of React hooks when working and using them in your React projects to avoid experiencing errors like this.

Looking for the ideal hosting solution for your React applications? Give Kinsta’s Application hosting a try for free!

We want to hear from you! Have you ever experienced this error before? If so, how did you resolve it? Did you use any other approaches that weren’t covered in this article? Share your thoughts in the comments section below!