Πώς να διορθώσετε το σφάλμα “Cannot Read Properties of Undefined (Reading map)” στο React

Το σφάλμα του React Cannot read properties of undefined (reading 'map') σημαίνει ότι η JavaScript προσπάθησε να αξιολογήσει κάτι σαν το items.map(...) ενώ το items ήταν undefined. Το σημαντικό μέρος δεν είναι η λέξη map, αλλά η τιμή που βρίσκεται αμέσως πριν από το .map().

Η τρέχουσα τεκμηρίωση του React (React 19.2 κατά τη στιγμή της σύνταξης) εξακολουθεί να χρησιμοποιεί τη μέθοδο map() των πινάκων της JavaScript ως τον τυπικό τρόπο μετατροπής συλλογών σε στοιχεία JSX. Το MDN ορίζει το Array.prototype.map() ως μια μέθοδο που δημιουργεί έναν νέο πίνακα εφαρμόζοντας μια callback σε κάθε στοιχείο. Εάν η τιμή που περιμένετε να είναι πίνακας δεν έχει αρχικοποιηθεί, δεν έχει φορτωθεί ακόμη ή προέρχεται από μια μη αναμενόμενη δομή API, η κλήση μπορεί να αποτύχει πριν το React μπορέσει να αποδώσει τη λίστα. Δείτε τον οδηγό του React για την απόδοση λιστών και την αναφορά του MDN για το Array.prototype.map().

Παραδειγματικό σενάριο: μια λίστα προϊόντων που καταρρέει πριν ολοκληρωθεί το API

Αυτό είναι ένα υποθετικό παράδειγμα για επεξήγηση, όχι πραγματικό αποτέλεσμα δοκιμής. Φανταστείτε ένα μικρό εξάρτημα καταστήματος που ανακτά προϊόντα μετά την πρώτη εμφάνιση του εξαρτήματος. Ο προγραμματιστής γράφει:

function ProductList() {
  const [products, setProducts] = useState();

  useEffect(() => {
    fetch('/api/products')
      .then(response => response.json())
      .then(data => setProducts(data));
  }, []);

  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

Στην πρώτη απόδοση, το products είναι undefined επειδή δεν δόθηκε αρχική τιμή στο useState. Η τεκμηρίωση του useState του React αναφέρει ότι η τιμή κατάστασης στην πρώτη απόδοση ταιριάζει με την αρχική κατάσταση που παρέχετε. Το fetch εκτελείται στη συνέχεια, οπότε η απόδοση μπορεί να φτάσει στο products.map(...) πριν φτάσει η απάντηση. Αναφορά React useState.

Εικόνα που δημιουργήθηκε από AI δείχνοντας την κονσόλα του browser με το σφάλμα Cannot read properties of undefined reading map σε ένα εξάρτημα React.
Εικόνα που δημιουργήθηκε από AI δείχνοντας το σφάλμα JavaScript που δείχνει σε μια απόδοση λίστας που καλεί .map() σε μια τιμή undefined.

Βήμα 1: Βρείτε ακριβώς ποια τιμή είναι undefined

Ξεκινήστε από το stack trace και εντοπίστε τη γραμμή που περιέχει το .map(). Στο παραδειγματικό εξάρτημα, αυτή η γραμμή είναι products.map(...), οπότε το products είναι η πρώτη τιμή προς επιθεώρηση. Σε ένα μεγαλύτερο εξάρτημα, η αποτυχημένη έκφραση μπορεί αντίθετα να είναι data.items.map(), props.users.map() ή response.results.map().

Χρησιμοποιήστε τον debugger του browser ή μια προσωρινή καταγραφή αμέσως πριν από τη λογική απόδοσης:

console.log('products:', products);
console.log('is array:', Array.isArray(products));

Αυτό διαχωρίζει διάφορα bugs που φαίνονται παρόμοια στο UI. Εάν η τιμή είναι undefined, ερευνήστε την αρχικοποίηση ή μια λείπουσα ιδιότητα. Εάν είναι null, το μοντέλο φόρτωσης/δεδομένων σας μπορεί να χρησιμοποιεί ρητά το null. Εάν είναι αντικείμενο, μπορεί να διαβάζετε το λάθος επίπεδο μιας απάντησης API. Εάν είναι συμβολοσειρά ή αριθμός, η σύμβαση δεδομένων της πηγής διαφέρει από αυτό που περιμένει το εξάρτημα.

Μην αντικαθιστάτε αυτόματα κάθε αποτυχημένη έκφραση με προαιρετική αλυσίδα (optional chaining) πριν κατανοήσετε την τιμή. Αυτό μπορεί να καταστείλει την κατάρρευση ενώ αφήνει λανθασμένη ροή δεδομένων στη θέση της.

Βήμα 2: Αρχικοποιήστε την κατάσταση συλλογής ως συλλογή όταν αυτό ταιριάζει με το μοντέλο σας

Για την υποθετική λίστα προϊόντων, ένας κενός πίνακας είναι μια λογική αρχική κατάσταση επειδή το “δεν έχουν φορτωθεί προϊόντα ακόμα” μπορεί να αναπαρασταθεί με ασφάλεια ως μια συλλογή με μηδέν στοιχεία:

const [products, setProducts] = useState([]);

Τώρα η πρώτη απόδοση μπορεί να εκτελέσει το products.map(...) επειδή ένας κενός πίνακας έχει μέθοδο map. Όταν το αίτημα ενημερώσει αργότερα την κατάσταση, το React αποδίδει ξανά με τα επιστραφέντα προϊόντα.

Εικόνα που δημιουργήθηκε από AI δείχνοντας μια δήλωση React useState αρχικοποιημένη με έναν κενό πίνακα.
Εικόνα που δημιουργήθηκε από AI δείχνοντας την αρχικοποίηση κατάστασης λίστας με useState([]) ώστε η πρώτη απόδοση να έχει έναν πίνακα.

Αυτή είναι μια ισχυρή διόρθωση όταν η κατάσταση είναι εννοιολογικά πάντα ένας πίνακας. Είναι λιγότερο κατάλληλη όταν το undefined ή το null μεταφέρει σημαντικές πληροφορίες, όπως “δεν έχει ζητηθεί ακόμα”, ενώ το [] σημαίνει “το αίτημα ολοκληρώθηκε και υπάρχουν μηδέν αποτελέσματα”. Σε αυτή την περίπτωση, κρατήστε τις καταστάσεις διακριτές και αποδώστε ρητά τις συνθήκες φόρτωσης, σφάλματος και κενού.

Βήμα 3: Επαληθεύστε τη δομή της απάντησης του API πριν την τοποθετήσετε στην κατάσταση

Η αρχικοποίηση διορθώνει μόνο την πρώτη απόδοση. Δεν θα προστατεύσει το εξάρτημα εάν ο διακομιστής επιστρέψει τελικά μια διαφορετική δομή. Υποθέστε ότι το API επιστρέφει στην πραγματικότητα:

{
  "products": [
    { "id": 1, "name": "Keyboard" },
    { "id": 2, "name": "Mouse" }
  ]
}

Τότε το setProducts(data) αποθηκεύει ένα αντικείμενο, όχι έναν πίνακα. Το πιθανό σφάλμα αλλάζει σε κάτι σαν το products.map is not a function. Η σωστή ανάθεση θα ήταν setProducts(data.products), εφόσον αυτή η ιδιότητα είναι εγγυημένο ότι είναι πίνακας.

Για δεδομένα που διασχίζουν ένα εξωτερικό όριο, επαληθεύστε τα:

fetch('/api/products')
  .then(response => response.json())
  .then(data => {
    if (!Array.isArray(data.products)) {
      throw new Error('Expected data.products to be an array');
    }
    setProducts(data.products);
  })
  .catch(error => {
    console.error(error);
    setError(error);
  });
Εικόνα που δημιουργήθηκε από AI δείχνοντας ένα εξάρτημα React που ελέγχει με Array.isArray πριν καλέσει το map.
Εικόνα που δημιουργήθηκε από AI δείχνοντας την προστασία μιας απόδοσης λίστας με Array.isArray() πριν χρησιμοποιήσετε το .map().

Αυτό έχει σημασία επειδή μια “ασφαλής προεπιλογή” δεν πρέπει να μετατρέπει κακοσχηματισμένα δεδομένα παραγωγής σε μια σιωπηρά κενή σελίδα. Εάν ένας πίνακας απαιτείται από τη σύμβαση, η καταγραφή ή η εμφάνιση ενός σφάλματος μπορεί να είναι πιο χρήσιμη από το να μετατρέπεται κάθε μη αναμενόμενη απάντηση σε [].

Βήμα 4: Επιλέξτε τον σωστό μηχανισμό απόδοσης για δεδομένα που μπορεί δικαιολογημένα να λείπουν

Το React υποστηρίζει τη φυσιολογική δεσμευτική απόδοση της JavaScript. Τα επίσημα έγγραφα δείχνουν τη χρήση if, τριαδικών εκφράσεων και && για να αποφασίσετε ποιο JSX να επιστραφεί. Οδηγός δεσμευτικής απόδοσης του React.

Για την υποθετική σελίδα προϊόντων, μια ρητή ροή φόρτωσης και σφάλματος είναι συχνά η πιο σαφής:

if (error) {
  return <p>Could not load products.</p>;
}

if (products === undefined) {
  return <p>Loading products…</p>;
}

if (products.length === 0) {
  return <p>No products found.</p>;
}

return (
  <ul>
    {products.map(product => (
      <li key={product.id}>{product.name}</li>
    ))}
  </ul>
);

Η προαιρετική αλυσίδα είναι επίσης έγκυρη όταν το “λείπει προς το παρόν” πρέπει απλώς να παράγει κανένα αποτέλεσμα χαρτογράφησης:

{products?.map(product => (
  <ProductCard key={product.id} product={product} />
))}

Το MDN εξηγεί ότι η προαιρετική αλυσίδα (?.) διακόπτει τη ροή όταν η τιμή στα αριστερά της είναι null ή undefined αντί να προκαλέσει ένα TypeError. Αναφορά προαιρετικής αλυσίδας του MDN.

Εικόνα που δημιουργήθηκε από AI δείχνοντας προαιρετική αλυσίδα χρησιμοποιημένη πριν το map σε ένα εξάρτημα React.
Εικόνα που δημιουργήθηκε από AI δείχνοντας προαιρετική αλυσίδα με users?.map(...) για δεδομένα που μπορεί προσωρινά να είναι undefined.

Ο περιορισμός είναι σημαντικός: το products?.map(...) αποτρέπει αυτό το συγκεκριμένο σφάλμα πρόσβασης σε nullish τιμή, αλλά δεν αποδεικνύει ότι το products είναι πίνακας. Εάν το products γίνει αντικείμενο, το products?.map εξακολουθεί να επιλύεται σε μια undefined ιδιότητα και η προσπάθεια κλήσης του μπορεί να αποτύχει. Χρησιμοποιήστε επαλήθευση σχήματος ή Array.isArray() όταν ο τύπος δεδομένων είναι αβέβαιος.

Ποια διόρθωση πρέπει να επιλέξετε;

ΚατάστασηΚαλύτερη πρώτη κίνησηΓιατί
Η κατάσταση πρέπει πάντα να είναι λίσταuseState([])Δίνει στην πρώτη απόδοση τον σωστό τύπο δεδομένων.
Τα λείποντα δεδομένα έχουν μια σημαντική κατάσταση φόρτωσηςΔεσμευτική απόδοσηΚρατά το “δεν έχει φορτωθεί” ξεχωριστό από το “φορτώθηκε αλλά είναι κενό”.
Η δομή του API μπορεί να ποικίλλει ή να είναι κακοσχηματισμένηΕπαλήθευση με Array.isArray() ή σχήμαΑποτρέπει την είσοδο κακών εξωτερικών δεδομένων στην κατάσταση του εξαρτήματος απαρατήρητα.
Η ιδιότητα (prop) είναι προαιρετική από σχεδιασμόΠροαιρετική αλυσίδα ή προεπιλεγμένη τιμή propΑποφεύγει την αναφορά σε μια δικαιολογημένα απουσιάζουσα τιμή.
Το σφάλμα εμφανίζεται μετά από ένα refactorΕλέγξτε τα ονόματα ιδιοτήτων και propsΈνα μετονομασμένο πεδίο μπορεί να κάνει έναν πρώην έγκυρο πίνακα να γίνει undefined.

Συχνές περιπτώσεις που μοιάζουν με το ίδιο σφάλμα

Το API επιστρέφει { items: [...] }, αλλά το εξάρτημα περιμένει έναν πίνακα

Επιθεωρήστε την απάντηση Network και αναθέστε την ιδιότητα πίνακα αντί για το αντικείμενο περιέκτη. Μην μαντεύετε τη δομή από ένα παλιό παράδειγμα ή μια διεπαφή TypeScript εάν η ζωντανή απάντηση διαφέρει.

Ένα γονικό εξάρτημα ξεχνά να περάσει το prop

Αυτό θα αποτύχει:

function UserList({ users }) {
  return users.map(user => <div key={user.id}>{user.name}</div>);
}

// Parent accidentally omits users:
<UserList />

Εάν ένα παραλειπόμενο prop πρέπει να σημαίνει μια κενή λίστα, μια προεπιλογή κάνει αυτή τη σύμβαση ρητή:

function UserList({ users = [] }) {
  return users.map(user => <div key={user.id}>{user.name}</div>);
}

Μια ένθετη ιδιότητα λείπει

Με το response.data.items.map(...), οποιαδήποτε λείπουσα ενδιάμεση ιδιότητα μπορεί να προκαλέσει αποτυχία. Η προαιρετική αλυσίδα όπως response?.data?.items είναι χρήσιμη για την ανάδοση αβέβαιων ένθετων τιμών, αλλά επαληθεύστε την τελική συλλογή πριν τη χειριστείτε ως πίνακα.

Η πρώτη απόδοση συμβαίνει πριν ολοκληρωθεί ένα Effect fetch

Τα Effects του React εκτελούνται μετά την απόδοση. Η τεκμηρίωση του React σημειώνει επίσης ότι η χειροκίνητη ανάκτηση δεδομένων μέσα σε Effects είναι συνηθισμένη σε εφαρμογές client-side αλλά μπορεί να έχει μειονεκτήματα όπως waterfalls, λείποντα δεδομένα server-rendered και χειροκίνητη διαχείριση caching/race-condition. Εάν χρησιμοποιείτε ένα framework React, ο ενσωματωμένος μηχανισμός φόρτωσης δεδομένων του μπορεί να είναι μια καλύτερη αρχιτεκτονική επιλογή. Αναφορά React useEffect.

Μια ασφαλέστερη τελική έκδοση του παραδειγματικού εξαρτήματος

import { useEffect, useState } from 'react';

export default function ProductList() {
  const [products, setProducts] = useState(undefined);
  const [error, setError] = useState(null);

  useEffect(() => {
    let ignore = false;

    fetch('/api/products')
      .then(response => {
        if (!response.ok) throw new Error('Request failed');
        return response.json();
      })
      .then(data => {
        if (!Array.isArray(data.products)) {
          throw new Error('Expected products array');
        }
        if (!ignore) setProducts(data.products);
      })
      .catch(error => {
        if (!ignore) setError(error);
      });

    return () => {
      ignore = true;
    };
  }, []);

  if (error) return <p>Could not load products.</p>;
  if (products === undefined) return <p>Loading products…</p>;
  if (products.length === 0) return <p>No products found.</p>;

  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

Αυτή η έκδοση διακρίνει σκόπιμα το “δεν έχει φορτωθεί”, “απέτυχε”, “κενό” και “έχει δεδομένα”. Είναι πιο εκτενές από μια ενιαία έκφραση προαιρετικής αλυσίδας, αλλά δίνει στον χρήστη ένα σημαντικό UI για κάθε κατάσταση και κάνει μια κακοσχηματισμένη απάντηση API ορατή κατά την αποσφαλμάτωση.

Γρήγορη λίστα ελέγχου πριν θεωρήσετε το bug διορθωμένο

  • Εντοπίστε την ακριβή τιμή αμέσως πριν από το .map().
  • Επιβεβαιώστε την τιμή και τον τύπο της στην απόδοση που αποτυγχάνει.
  • Αρχικοποιήστε την κατάσταση λίστας με [] όταν ένας κενός πίνακας αναπαριστά ακριβώς την αρχική κατάσταση.
  • Ελέγξτε εάν το API επιστρέφει έναν πίνακα απευθείας ή τον τυλίγει σε μια ιδιότητα αντικειμένου.
  • Επαληθεύστε τα εξωτερικά δεδομένα πριν τα αποθηκεύσετε στην κατάσταση όταν η σύμβαση έχει σημασία.
  • Χρησιμοποιήστε μια κατάσταση φόρτωσης εάν το undefined σημαίνει “δεν έχει φορτωθεί ακόμα”.
  • Χρησιμοποιήστε προαιρετική αλυσίδα όταν η απουσία είναι δικαιολογημένη, όχι ως υποκατάστατο για την κατανόηση κακών δεδομένων.
  • Ελέγξτε μετονομασμένα ή παραλειπόμενα props μετά από refactors.
  • Δώστε στα αποδοθέντα στοιχεία λίστας σταθερά keys από τα δεδομένα, όπως συνιστάται από την τεκμηρίωση απόδοσης λιστών του React.

Για την υποθετική λίστα προϊόντων, η αιτία ρίζας ήταν η πρώτη απόδοση να λαμβάνει undefined όπου το εξάρτημα περίμενε αμέσως έναν πίνακα. Σε μια πραγματική εφαρμογή, το ίδιο μήνυμα σφάλματος μπορεί να προέρχεται από την αρχικοποίηση κατάστασης, τα props, τις ένθετες ιδιότητες ή τα δεδομένα του API. Διορθώστε πρώτα τη σύμβαση δεδομένων και στη συνέχεια επιλέξτε έναν μηχανισμό απόδοσης που αναπαριστά ακριβώς τι σημαίνει “λείπει” στο UI σας.

Αφήστε ένα σχόλιο

Πώς να διορθώσετε το σφάλμα "Τα στυλ CSS Tailwind δεν ενημερώνονται" σε μια εφαρμογή Vite React

Πώς να διορθώσετε το σφάλμα "Τα στυλ CSS Tailwind δεν ενημερώνονται" σε μια εφαρμογή Vite React

Διορθώστε τα στυλ CSS του Tailwind που δεν ενημερώνονται στο Vite React ελέγχοντας τη ρύθμιση του Tailwind v4, τις εισαγωγές CSS, την ανίχνευση πηγαίου κώδικα, τις δυναμικές κλάσεις, το HMR και τις παλιές προσωρινές μνήμες.

Πώς να διορθώσετε το σφάλμα ModuleNotFoundError: Δεν υπάρχει ενότητα με το όνομα 'pip' στην Python 3

Πώς να διορθώσετε το σφάλμα ModuleNotFoundError: Δεν υπάρχει ενότητα με το όνομα 'pip' στην Python 3

Διορθώστε το σφάλμα ModuleNotFoundError της Python 3 για το pip σε Windows, macOS και Linux με το ensurepip, πακέτα λειτουργικού συστήματος, εικονικά περιβάλλοντα και ελέγχους διερμηνέα.

Πώς να διορθώσετε το σφάλμα "Άρνηση άδειας (δημόσιο κλειδί)" στο GitHub SSH

Πώς να διορθώσετε το σφάλμα "Άρνηση άδειας (δημόσιο κλειδί)" στο GitHub SSH

Διορθώστε το πρόβλημα "Απόρριψη άδειας SSH GitHub (publickey)" ελέγχοντας τον κεντρικό υπολογιστή, το ενεργό κλειδί SSH, τον λογαριασμό GitHub, την εξουσιοδότηση SSO, την απομακρυσμένη διεύθυνση URL και την πρόσβαση στη θύρα 22.

Πώς να διορθώσετε το σφάλμα "Git Push Rejected: Non-Fast-Forward" χωρίς να χάσετε αλλαγές

Πώς να διορθώσετε το σφάλμα "Git Push Rejected: Non-Fast-Forward" χωρίς να χάσετε αλλαγές

Διορθώστε με ασφάλεια μια μη γρήγορη προώθηση σε Git. Προστατέψτε την τοπική εργασία, ανακτήστε απομακρυσμένες υποβολές, επιλέξτε συγχώνευση ή αλλαγή βάσης, επιλύστε διενέξεις και προωθήστε χωρίς να χάσετε αλλαγές.

Πώς να διορθώσετε το σφάλμα "Nginx 502 Bad Gateway" κατά τη μεσολάβηση στο Node.js

Πώς να διορθώσετε το σφάλμα "Nginx 502 Bad Gateway" κατά τη μεσολάβηση στο Node.js

Διορθώστε τα σφάλματα Nginx 502 Bad Gateway με ένα Node.js upstream ελέγχοντας τη θύρα εφαρμογής, τα αρχεία καταγραφής NGINX, τη διεύθυνση proxy_pass, τη δικτύωση κοντέινερ, τα χρονικά όρια και την επαναφόρτωση.

How to Fix “Type 'null' Is Not Assignable to Type” in TypeScript

How to Fix “Type 'null' Is Not Assignable to Type” in TypeScript

Fix TypeScript's “Type 'null' is not assignable to type” error with union types, narrowing, defaults, and safe assertions under strictNullChecks.

Πώς να διορθώσετε το σφάλμα «Το Prisma Client δεν έχει δημιουργηθεί ακόμη»

Πώς να διορθώσετε το σφάλμα «Το Prisma Client δεν έχει δημιουργηθεί ακόμη»

Διορθώστε το σφάλμα μη δημιουργημένου Prisma Client ελέγχοντας τον generator, το schema, τη διαδρομή εξόδου, τα imports, τις εκδόσεις, τη ρύθμιση monorepo και τα βήματα build της ανάπτυξης.

Πώς να διορθώσετε το σφάλμα "ERR_MODULE_NOT_FOUND" στις εισαγωγές ESM του Node.js

Πώς να διορθώσετε το σφάλμα "ERR_MODULE_NOT_FOUND" στις εισαγωγές ESM του Node.js

Διορθώστε το σφάλμα Node.js ERR_MODULE_NOT_FOUND στο ESM ελέγχοντας τις διαδρομές εισαγωγής, τις επεκτάσεις αρχείων, την εγκατάσταση πακέτων, τις εξαγωγές, τη λειτουργία ESM και τις καθαρές εγκαταστάσεις.

Πώς να διορθώσετε το πρόβλημα πιστοποιητικού SSL: Unable to Get Local Issuer Certificate στο Git

Πώς να διορθώσετε το πρόβλημα πιστοποιητικού SSL: Unable to Get Local Issuer Certificate στο Git

Διορθώστε το σφάλμα του Git «unable to get local issuer certificate» εντοπίζοντας το backend εμπιστοσύνης, εγκαθιστώντας τη σωστή αλυσίδα CA και διατηρώντας ενεργή την επαλήθευση SSL.

Πώς να διορθώσετε το σφάλμα λήξης χρόνου δικτύου του MongoDB στη σύνδεση Mongoose

Πώς να διορθώσετε το σφάλμα λήξης χρόνου δικτύου του MongoDB στη σύνδεση Mongoose

Διορθώστε τα σφάλματα λήξης χρόνου δικτύου του MongoDB στο Mongoose εντοπίζοντας τον τύπο λήξης, ελέγχοντας την προσβασιμότητα Atlas ή TCP, διορθώνοντας το URI και ρυθμίζοντας τα timeouts μόνο όταν δικαιολογείται.