Hogyan javítsd a „Cannot Read Properties of Undefined (Reading map)” hibát Reactben

A React Cannot read properties of undefined (reading 'map') hibaüzenete azt jelenti, hogy a JavaScript megpróbált kiértékelni egy olyan kifejezést, mint az items.map(...), miközben az items értéke undefined volt. A lényeg nem a map szó, hanem az a érték, amely közvetlenül a .map() előtt áll.

Az aktuális React dokumentáció (írásunk pillanatában a React 19.2) továbbra is a JavaScript tömb map() módszerét használja a gyűjtemények JSX elemekké alakításának szabványos módjaként. Az MDN az Array.prototype.map()-ot úgy definiálja, mint egy módszert, amely új tömböt hoz létre egy callback függvény minden elemre történő alkalmazásával. Ha az az érték, amelyről azt várjuk, hogy tömb legyen, nincs inicializálva, még nem töltődött be, vagy egy váratlan API-válaszból származik, a hívás sikertelen lehet, mielőtt a React renderelhetné a listát. Lásd a React útmutatóját a listák rendereléséhez és az MDN Array.prototype.map() referenciáját.

Illusztratív forgatókönyv: egy terméklista, amely összeomlik, mielőtt az API befejezné

Ez egy hipotetikus példa a magyarázat céljából, nem valós tesztelési eredmény. Képzeljünk el egy kis áruház komponenst, amely a komponens megjelenése után tölti be a termékeket. A fejlesztő a következő kódot írja:

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>
  );
}

Az első rendereléskor a products értéke undefined, mert nem adtunk át kezdeti értéket a useState-nek. A React useState dokumentációja kimondja, hogy az állapot értéke az első rendereléskor megegyezik a megadott kezdeti állapottal. A fetch futás ezután következik, így a renderelés elérheti a products.map(...) részt, mielőtt a válasz megérkezik. React useState referencia.

AI-generált illusztráció a böngésző konzolról, amely a Cannot read properties of undefined reading map hibaüzenetet mutatja egy React komponensben.
AI-generált illusztráció a JavaScript hibáról, amely egy olyan lista renderelésére mutat, amely .map()-ot hív egy undefined értéken.

1. lépés: Találd meg pontosan, melyik érték undefined

Kezdd a stack trace-nél, és keresd meg azt a sort, amely tartalmazza a .map()-ot. Az illusztratív komponensben ez a sor a products.map(...), tehát a products az első ellenőrizendő érték. Egy nagyobb komponensben a hibás kifejezés lehet data.items.map(), props.users.map() vagy response.results.map() is.

Használd a böngésző hibakeresőjét vagy egy ideiglenes naplózási utasítást közvetlenül a renderelési logika előtt:

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

Ez szétválaszt több, a felhasználói felületen hasonlóan kinéző hibát. Ha az érték undefined, vizsgálja meg az inicializálást vagy egy hiányzó tulajdonságot. Ha null, a betöltési/adatmodellje explicit módon használhat nullt. Ha objektum, akkor lehet, hogy az API-válasz rossz szintjét olvassa. Ha string vagy szám, a felsőbb réteg adatkontraktuma eltér attól, amit a komponens vár.

Ne automatikusan cseréld le minden hibás kifejezést opcionális láncolásra, mielőtt megértenéd az értéket. Ez elfojthatja az összeomlást, miközben a hibás adatfolyam a helyén marad.

2. lépés: Inicializáld a gyűjtemény állapotát gyűjteményként, ha ez megfelel a modellnek

A hipotetikus terméklista esetén egy üres tömb ésszerű kezdeti állapot, mert a „még nem töltődtek be termékek” biztonságosan reprezentálható nulla elemű gyűjteményként:

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

Most az első renderelés futtathatja a products.map(...)-ot, mert egy üres tömbnek van map módszere. Amikor a kérés később frissíti az állapotot, a React újra renderel a visszakapott termékekkel.

AI-generált illusztráció egy React useState deklarációról, amely üres tömbbel van inicializálva.
AI-generált illusztráció a lista állapotának inicializálásáról useState([]) segítségével, hogy az első renderelésnek legyen tömbje.

Ez erős megoldás, ha az állapot fogalmilag mindig tömb. Kevésbé megfelelő, ha az undefined vagy null jelentőséggel bír, például „még nem kérték le”, míg a [] azt jelenti, hogy „a kérés befejeződött, és nulla eredmény van”. Ebben az esetben tartsd külön az állapotokat, és jelenítsd meg explicit módon a betöltési, hiba és üres feltételeket.

3. lépés: Ellenőrizd az API-válasz struktúráját, mielőtt az állapotba helyeznéd

Az inicializálás csak az első renderelést javítja meg. Nem védi meg a komponenst, ha a szerver végül más struktúrát ad vissza. Tegyük fel, hogy az API valójában ezt adja vissza:

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

Ekkor a setProducts(data) egy objektumot tárol, nem tömböt. A valószínű hiba valami olyasmivé válik, mint a products.map is not a function. A helyes hozzárendelés a setProducts(data.products) lenne, feltéve, hogy ez a tulajdonság garantáltan tömb.

Külső határt átlépő adatok esetén validáld őket:

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-generált illusztráció egy React komponensről, amely Array.isArray ellenőrzést végez a map hívása előtt.
AI-generált illusztráció a lista renderelésének védelméről Array.isArray() használatával a .map() előtt.

Ez azért fontos, mert egy „biztonságos alapértelmezés” nem alakíthatja át a hibás éles adatokat csendben üres oldallá. Ha a szerződés szerint tömb szükséges, a naplózás vagy a hiba megjelenítése hasznosabb lehet, mint minden váratlan válasz []-ra alakítása.

4. lépés: Válaszd ki a megfelelő renderelési védelmet a jogosan hiányzó adatokhoz

A React támogatja a normál JavaScript feltételes renderelést. A hivatalos dokumentáció azt mutatja, hogyan használhatók az if, a ternáris kifejezések és a && a visszaadandó JSX eldöntésére. React feltételes renderelési útmutató.

A hipotetikus termékoldalon egy explicit betöltési és hibaáram gyakran a legátláthatóbb:

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>
);

Az opcionális láncolás is érvényes, ha a „jelenleg hiányzik” egyszerűen nem eredményez leképezett kimenetet:

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

Az MDN elmagyarázza, hogy az opcionális láncolás (?.) megszakítja a végrehajtást, ha a bal oldali értéke null vagy undefined, ahelyett, hogy TypeErro-t dobna. MDN opcionális láncolási referencia.

AI-generált illusztráció az opcionális láncolásról a map előtt egy React komponensben.
AI-generált illusztráció az opcionális láncolásról users?.map(...) formában ideiglenesen undefined adatok esetén.

A korlát fontos: a products?.map(...) megakadályozza ezt a konkrét nullish-hozzáférési hibát, de nem bizonyítja, hogy a products tömb. Ha a products objektummá válik, a products?.map továbbra is egy undefined tulajdonságra hivatkozik, és a hívása továbbra is sikertelen lehet. Használj sémavalidációt vagy Array.isArray()-t, ha maga az adattípus bizonytalan.

Melyik megoldást válaszd?

HelyzetLegjobb első lépésMiért
Az állapotnak mindig listának kell lennieuseState([])Megadja az első renderelésnek a helyes adattípust.
A hiányzó adatnak jelentős betöltési állapota vanFeltételes renderelésKülön tartja a „nem betöltött” és a „betöltött, de üres” állapotot.
Az API struktúrája változó vagy hibás lehetValidálás Array.isArray()-vel vagy sémávalMegakadályozza, hogy a rossz külső adat észrevétlenül kerüljön a komponens állapotába.
A prop tervezés szerint opcionálisOpcionális láncolás vagy alapértelmezett prop értékKerüli a jogosan hiányzó érték de-referenciálását.
A hiba refaktorálás után jelenik megEllenőrizd a tulajdonság- és propneveketEgy átnevezett mező miatt egy egykor érvényes tömb undefineddé válhat.

Gyakori esetek, amelyek ugyanannak a hibának tűnnek

Az API { items: [...] }-t ad vissza, de a komponens tömböt vár

Vizsgáld meg a Network választ, és a wrapper objektum helyett a tömb tulajdonságot rendeld hozzá. Ne találgasd a struktúrát egy régi példából vagy TypeScript interfészből, ha az élő válasz eltér.

Egy szülő komponens elfelejti átadni a propot

Ez fog elbukni:

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

// A szülő véletlenül kihagyja a users propot:
<UserList />

Ha egy kihagyott propnak üres listát kell jelentenie, egy alapértelmezett érték explicitéssé teszi ezt a szerződést:

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

Egy beágyazott tulajdonság hiányzik

A response.data.items.map(...) esetén bármely hiányzó köztes tulajdonság okozhat hibát. Az opcionális láncolás, mint a response?.data?.items, hasznos bizonytalan beágyazott értékek olvasásához, de validáld a végső gyűjteményt, mielőtt tömbként kezelnéd.

Az első renderelés megtörténik, mielőtt a fetch Effect befejeződik

A React Effects a renderelés után futnak. A React dokumentációja azt is megjegyzi, hogy az adatok manuális lekérése az Effects-en belül gyakori kliensoldali alkalmazásokban, de hátrányai lehetnek, mint például a vízesésszerű hívások, a hiányzó szerveroldali renderelt adatok, valamint a manuális gyorsítótárazási/versenyfeltétel-munka. Ha React keretrendszert használsz, annak beépített adatbetöltési mechanizmusa jobb architekturális választás lehet. React useEffect referencia.

Az illusztratív komponens biztonságosabb végső verziója

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>
  );
}

Ez a verzió szándékosan különbséget tesz a „nem betöltött”, „sikertelen”, „üres” és „van adat” állapotok között. Ez bőbeszédűbb, mint egyetlen opcionális láncolási kifejezés, de a felhasználónak minden állapothoz jelentőségteljes UI-t biztosít, és debugolás közben láthatóvá teszi a hibás API-válaszokat.

Gyors ellenőrzőlista, mielőtt a hibát javítottnak tekinted

  • Azonosítsd a .map() előtt álló pontos értéket.
  • Erősítsd meg az értékét és típusát a hibás renderelésnél.
  • Inicializáld a lista állapotát []-vel, ha az üres tömb pontosan reprezentálja a kezdeti állapotot.
  • Ellenőrizd, hogy az API közvetlenül tömböt ad-e vissza, vagy egy objektum tulajdonságba csomagolja.
  • Validáld a külső adatokat, mielőtt az állapotba mentenéd őket, ha a szerződés fontos.
  • Használj betöltési állapotot, ha az undefined azt jelenti, hogy „még nem töltődött be”.
  • Használj opcionális láncolást, ha a hiány jogos, ne pedig a rossz adatok megértésének helyettesítőjeként.
  • Ellenőrizd az átnevezett vagy kihagyott propokat refaktorálások után.
  • Adj a renderelt listaelemeknek stabil kulcsokat az adatokból, ahogy a React listarendezési dokumentációja javasolja.

A hipotetikus terméklista esetén a gyökérok az volt, hogy az első renderelés undefined-t kapott ott, ahol a komponens azonnal tömböt várt. Egy valós alkalmazásban ugyanaz a hibaüzenet származhat állapotinicializálásból, propokból, beágyazott tulajdonságokból vagy API-adatokból. Először javítsd az adatkontraktumot, majd válassz egy renderelési védelmet, amely pontosan reprezentálja, mit jelent a „hiányzik” a felhasználói felületeden.

Hagyj kommentárt

How to Fix "Tailwind CSS Styles Not Updating" in a Vite React App

How to Fix "Tailwind CSS Styles Not Updating" in a Vite React App

Fix Tailwind CSS styles not updating in Vite React by checking Tailwind v4 setup, CSS imports, source detection, dynamic classes, HMR, and stale caches.

Hogyan javítsuk ki a ModuleNotFoundError hibát: Nincs 'pip' nevű modul Python 3-ban

Hogyan javítsuk ki a ModuleNotFoundError hibát: Nincs 'pip' nevű modul Python 3-ban

Javítsd ki a Python 3 ModuleNotFoundError hibáját a pip esetében Windows, macOS és Linux rendszereken ensurepip, operációsrendszer-csomagok, virtuális környezetek és interpreter-ellenőrzések segítségével.

A „Hozzáférés megtagadva (nyilvános kulcs)” hiba javítása a GitHub SSH-ban

A „Hozzáférés megtagadva (nyilvános kulcs)” hiba javítása a GitHub SSH-ban

Javítsd ki a GitHub SSH engedély megtagadva (nyilvános kulcs) hibát a gazdagép, az aktív SSH kulcs, a GitHub fiók, az SSO-engedélyezés, a távoli URL és a 22-es port hozzáférésének ellenőrzésével.

Hogyan javítsuk ki a „Git Push elutasítva: nem gyorsított előretekerés” hibát a változtatások elvesztése nélkül

Hogyan javítsuk ki a „Git Push elutasítva: nem gyorsított előretekerés” hibát a változtatások elvesztése nélkül

Git nem gyorsított push hiba javítása biztonságosan. Helyi munka védelme, távoli commitok beolvasása, egyesítés vagy újraalapozás kiválasztása, ütközések feloldása és push végrehajtása a változtatások elvesztése nélkül.

Hogyan javítsuk ki az „Nginx 502 Bad Gateway” hibát Node.js proxy használatakor

Hogyan javítsuk ki az „Nginx 502 Bad Gateway” hibát Node.js proxy használatakor

Javítsd ki az Nginx 502 Bad Gateway hibákat egy Node.js upstream fájllal az alkalmazásport, az NGINX naplók, a proxy_pass cím, a konténerhálózat, az időtúllépések és az újratöltés ellenőrzésével.

Hogyan javítsuk ki a „Type 'null' Is Not Assignable to Type” hibát TypeScriptben?

Hogyan javítsuk ki a „Type 'null' Is Not Assignable to Type” hibát TypeScriptben?

Kijavítottuk a TypeScript „A 'null' típus nem rendelhető típushoz” hibáját uniótípusokkal, szűkítéssel, alapértelmezett értékekkel és biztonságos állításokkal a strictNullChecks alatt.

Hogyan javítsuk ki a „Prisma Client has not been generated yet” hibát

Hogyan javítsuk ki a „Prisma Client has not been generated yet” hibát

Javítsa ki a Prisma Client nem generált hibát a generátor, a séma, a kimeneti útvonal, az importok, a verziók, a monorepo beállítás és a telepítési build lépések ellenőrzésével.

Az „ERR_MODULE_NOT_FOUND” hiba javítása a Node.js ESM importálásokban

Az „ERR_MODULE_NOT_FOUND” hiba javítása a Node.js ESM importálásokban

Javítsd ki a Node.js ERR_MODULE_NOT_FOUND hibát az ESM-ben az importálási útvonalak, fájlkiterjesztések, csomagtelepítés, exportálások, ESM mód és tiszta telepítések ellenőrzésével.

Hogyan javítható az SSL-tanúsítvány hiba: Unable to Get Local Issuer Certificate Git esetén

Hogyan javítható az SSL-tanúsítvány hiba: Unable to Get Local Issuer Certificate Git esetén

Javítsd ki a Git 'unable to get local issuer certificate' hibáját a megbízható háttérprogram azonosításával, a helyes CA-lánc telepítésével, és az SSL-ellenőrzés engedélyezve tartásával.

Hogyan javítsuk meg a MongoDB hálózati időtúllépési hibát a Mongoose kapcsolódásnál

Hogyan javítsuk meg a MongoDB hálózati időtúllépési hibát a Mongoose kapcsolódásnál

Javítsa a Mongoose MongoDB hálózati időtúllépési hibáit az időtúllépés típusának azonosításával, az Atlas vagy TCP elérhetőség tesztelésével, az URI helyesbítésével, és az időtúllépések beállításával csak akkor, ha az indokolt.