Gli hook hanno rivoluzionato il modo di scrivere componenti funzionali in React, fornendo un modo conciso ed efficiente per gestire lo stato e gli effetti collaterali.

Tuttavia, come ogni nuova funzionalità, anche questa è accompagnata da una serie di regole e linee guida. Un errore frequente in cui possono imbattersi sviluppatori e sviluppatrici React è l’errore “react hooks must be called in a react function component or a custom react hook function”.

In questo articolo analizzeremo nel dettaglio questo errore, capiremo perché si verifica e descriveremo le best practice per risolverlo.

Cosa causa l’errore “React Hooks Must Be Called In a React Function Component or a Custom React Hook Function”?

Per utilizzare gli hook di React vanno seguite delle regole. Durante la fase di apprendimento, molti sviluppatori React ignorano queste regole, il che porta inevitabilmente a compiere degli errori. Uno di questi errori è “react hooks must be called in a react function component or a custom react hook function”.

Questo errore si verifica quando si verificano due cose:

  • Si utilizzano gli hook di React in componenti di classe
  • Si invocano gli hook di React all’interno di una funzione annidata

Gli hook di React, come useState, useEffect, e useContext, sono progettati per essere invocati al livello superiore di un componente funzionale o di una funzione hook personalizzata. Inoltre, dovrebbero essere invocati solo nei componenti funzionali e non in quelli di classe. Queste due regole garantiscono un uso corretto e coerente degli hook degli hook nei componenti React.

Quando gli hook vengono invocati in ambiti non corretti, si riceve questo errore: “react hooks must be called in a react function component or a custom react hook function”. Si tratta di un errore ESLint che permette di evitare che gli hook vengano utilizzati in modo da causare comportamenti inattesi e bug in un’applicazione React.

2 soluzioni per risolvere l’errore “React Hooks Must Be Called In a React Function Component or a Custom React Hook Function”

Questo errore può essere risolto in diversi modi, a seconda della situazione o dell’uso improprio che se ne è fatto.

1. Non utilizzare mai gli hook di React nei componenti di classe

Gli hook sono progettati per funzionare solo con componenti funzionali o hook personalizzati, perché utilizzano lo stack di chiamate dei componenti funzionali per gestire lo stato e il ciclo di vita del componente. I componenti di classe non hanno questo stack di chiamate, quindi non è possibile usare gli hook direttamente.

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;

Se lo fate, otterrete questo errore:

Errore della funzione React
Errore

Ma ci sono diversi modi per risolvere questo problema, a seconda delle proprie preferenze. Si può decidere di utilizzare state e setState con i componenti di classe, convertire il componente in un componente funzionale o utilizzare un componente di ordine superiore (HOC).

A. Convertire il componente di classe in un componente funzionale

Gli hook possono funzionare solo in un componente funzionale.

Nell’esempio che segue, il componente di classe precedente viene convertito in un componente funzionale:

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. Utilizzare un componente di ordine superiore (HOC)

Per utilizzare gli hook in un componente di classe si può utilizzare un componente di ordine superiore (HOC).

Un componente di ordine superiore è una funzione che prende un componente e restituisce un nuovo componente con oggetti o funzionalità aggiuntive. Ecco un esempio di HOC in cui si forniscono gli hook a un componente di classe:

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. Utilizzare gli Stati in un componente di classe

Infine, se non si vuole cambiare la sintassi del componente, si può decidere di utilizzare state e setState al posto di useState:

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. Non invocare mai gli hook di React all’interno di una funzione annidata

Una regola chiara degli hook di React è che tutti gli hook devono essere invocati al livello superiore di un componente funzionale o di una funzione hook personalizzata. Invocando un hook all’interno di una funzione annidata, si viola la regola.

Nell’esempio che segue, l’hook useState è invocato dalla funzione handleClick:

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;

In questo caso viene emesso il seguente errore:

Esempio di errore
Esempio di errore

Il problema si risolve spostando l’hook al di fuori della funzione, al livello superiore del componente funzionale:

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;

Riepilogo

In questo articolo abbiamo appreso quali sono le cause dell’errore “react hooks must be called in a react function component or a custom react hook function” e come risolverlo.

Seguite sempre le regole degli hook di React quando li utilizzate nei vostri progetti React per evitare di incorrere in errori come questo.

State cercando la soluzione di hosting ideale per le vostre applicazioni React? Provate gratuitamente l’Hosting di applicazioni di Kinsta!

Vogliamo sentire il vostro parere! Avete già riscontrato questo errore? Come l’avete risolto? Avete seguito altri approcci che non sono stati trattati in questo articolo? Scrivete un commento nella sezione qui sotto!