Sviluppando applicazioni React, ci si puù imbattere nel fastidioso errore “TypeError: Cannot Read Property ‘Map’ of Undefined”.

Il debug può essere complicato, ma questa guida aiuterà sia sviluppatori React esperti che alle prime armi a rimettere in sesto la propria applicazione, analizzando le cause e le soluzioni più comuni per risolvere questo errore.

Quali sono le cause dell’errore “TypeError: Cannot Read Property ‘Map’ of Undefined”?

L’errore “TypeError: Cannot Read Property ‘Map’ of Undefined” di solito si verifica quando si cerca di accedere a una proprietà o a un metodo di un valore non definito nel codice React.

In sintesi, l’errore si verifica quando si cerca di mappare un valore non definito, come ad esempio un array che non è stato inizializzato o che non ha ancora ricevuto dati.

Nell’esempio che segue, riceviamo elementi di todo dai dati del JSON Placeholder, ma il metodo map viene invocato prima che i dati di una richiesta all’API siano arrivati.

import { useState, useEffect } from 'react';

function App() {
  const [todos, setTodos] = useState();

  useEffect(() => {
    const getTodos = async () => {
      const response = await fetch(
        'https://jsonplaceholder.typicode.com/todos?_limit=5'
      );
      const data = await response.json();
      setTodos(data);
    };
    getTodos();
  }, []);

  console.log(todos);

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo.id}>
          <h2>Item: {todo.title}</h2>
        </div>
      ))}
    </div>
  );
}

export default App;

Il codice qui sopra emetterà il messaggio “TypeError: Cannot read properties of undefined (reading ‘map’)”:

Il Messaggio di errore TypeError: Cannot read properties of undefined (reading 'map')
Il Messaggio di errore TypeError: Cannot read properties of undefined (reading ‘map’)

Bisognerà cercare un modo per far sapere a React che lo stato todos è un array anche prima che l’array venga popolato, oppure evitare che il metodo map venga eseguito fino a che la variabile di stato todos non riceve i suoi dati dalla richiesta all’API.

3 metodi per risolvere l’errore “TypeError: Cannot Read Property ‘Map’ of Undefined”

Ecco tre metodi per risolvere l’errore “TypeError: Cannot Read Property ‘Map’ of Undefined” in React:

  1. Inizializzare la variabile di stato con un array vuoto
  2. Utilizzare gli operatori di confronto
  3. Utilizzare l’operatore di concatenamento opzionale (?.)

Analizziamo ognuna di queste soluzioni per risolvere l’errore nel codice React.

1. Inizializzare la variabile di stato in un array vuoto

Una delle soluzioni dirette all’errore “TypeError: Cannot Read Property ‘Map’ of Undefined” è definire la variabile array che si sta cercando di mappare.

È possibile inizializzare di default la variabile di stato ad un array vuoto in modo da assicurarsi che la variabile esista sempre e che non venga emesso un errore quando si cerca di mapparla.

Ad esempio, quelli che seguono sono due componenti simili: la variabile di stato del primo non è inizializzata ad un array vuoto, mentre è inizializzata nel secondo:

// Before initializing your state variable to an empty array
function MyComponent() {
  const [myList, setMyList] = useState();
  
  return (
    <ul>
      {myList.map(item => <li>{item}</li>)}
    </ul>
  );
}

// After initializing your state variable to an empty array
function MyComponent() {
  const [myList, setMyList] = useState([]);

  return (
    <ul>
      {myList.map(item => <li>{item}</li>)}
    </ul>
  );
}

Nell’esempio precedente, la variabile di stato myList viene inizializzata di default ad un array vuoto utilizzando useState([]). Questo fa sì che, anche se myList è inizialmente indefinito, sarà sempre un array e non emetterà il messaggio “TypeError: Cannot Read Property ‘Map’ of Undefined”.

Anche per l’esempio di fetch è possibile inizializzare la variabile di stato todos a un array vuoto ([]):

import { useState, useEffect } from 'react';

function App() {
  // Initialize the state to an empty array of todos.
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    const getTodos = async () => {
      const response = await fetch(
        'https://jsonplaceholder.typicode.com/todos?_limit=5'
      );
      const data = await response.json();
      setTodos(data);
    };
    getTodos();
  }, []);

  console.log(todos);

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo.id}>
          <h2>Item: {todo.title}</h2>
       </div>
      ))}
    </div>
  );
}

export default App;

2. Utilizzare gli operatori di confronto

Un’altra soluzione è quella di utilizzare gli operatori di confronto per verificare se la variabile dell’array è definita prima di eseguire la mappatura. A tale scopo è possibile utilizzare l’operatore ternario o logico AND (&&).

Ecco alcuni esempi che mostrano come utilizzare l’operatore ternario:

function MyComponent() {
  const [myList, setMyList] = useState();

  return (
    <ul>
      {myList ? myList.map(item => <li>{item}</li>) : null}
    </ul>
  );
}

In questo esempio, verifichiamo se la variabile dell’array myList è definita prima di provare a mapparla. Se myList non è definito, l’operatore ternario restituisce null e non viene visualizzato nulla. Se myList è definito, viene richiamata la funzione map e gli elementi dell’elenco vengono restituiti.

Con l’utilizzo dell’operatore logico AND si procede in modo simile:

function MyComponent() {
  const [myList, setMyList] = useState();

  return (
    <ul>
      {myList && myList.map(item => <li>{item}</li>)}
    </ul>
  );
}

Con gli operatori di confronto come l’operatore ternario, è possibile gestire il caricamento in modo da visualizzare qualcos’altro sullo schermo mentre si ricevono i dati dall’API:

import { useState, useEffect } from 'react';

function App() {
  const [todos, setTodos] = useState();

  useEffect(() => {
    const getTodos = async () => {
      const response = await fetch(
        'https://jsonplaceholder.typicode.com/todos?_limit=5'
      );
      const data = await response.json();
      setTodos(data);
    };
    getTodos();
  }, []);

  console.log(todos);

  return (
   <div>
      {todos ? (
        todos.map((todo) => (
          <div key={todo.id}>
            <h2>Item: {todo.title}</h2>
          </div>
        ))
      ) : (
        <h1>Loading...</h1>
      )}
    </div>
  );
}

export default App;

3. Utilizzare l’operatore di concatenamento opzionale (?.)

È anche possibile utilizzare l’operatore di concatenamento opzionale (?.) introdotto con ES2020. Questo operatore permette di accedere in modo sicuro a proprietà o metodi, come il metodo map di un array, senza che venga emesso un errore se l’array è indefinito.

In questo esempio vediamo un componente funzionale che utilizza l’operatore di concatenamento per controllare la variabile di stato myList:

function MyComponent() {
  const [myList, setMyList] = useState();

  return (
    <div>
      {myList?.map((item) => (
        <p>{item}</p>
      ))}
    </div>
  );
}

Nell’esempio qui sopra, utilizziamo l’operatore di concatenamento opzionale per accedere alla variabile dell’array myList in modo sicuro. Se myList è indefinito, non verrà visualizzato nulla. Se myList è definito, verrà invocato il metodo map e gli elementi dell’elenco verranno renderizzati.

Riepilogo

L’errore “TypeError: Cannot Read Property ‘Map’ of Undefined” di React può verificarsi quando si usa il metodo map su un valore non definito o nullo.

In questo articolo abbiamo descritto tre soluzioni per risolvere questo errore. Tuttavia, gli operatori di confronto offrono la soluzione più versatile perché possono gestire situazioni in cui l’API potrebbe inviare una risposta vuota o un valore nullo.

Inoltre, se non siete sicuri che i dati ricevuti siano in un array, potete aggiungere alcuni metodi per verificare e convertire il tipo di dati prima di chiamare il metodo map.

L’Hosting di Applicazioni di Kinsta è la soluzione ideale per il vostro prossimo progetto React. Provatelo oggi stesso!

Ora tocca a voi: avete mai riscontrato questo errore? Come l’avete risolto? Avete trovato altre soluzioni che non sono state trattate in questo articolo? Fatecelo sapere nei commenti!