Kako popraviti napako “Cannot Read Properties of Undefined (Reading map)” v Reactu

Napaka Reacta Cannot read properties of undefined (reading 'map') pomeni, da je JavaScript poskušal ovrednotiti nekaj, kot je items.map(...), medtem ko je bila vrednost items undefined. Pomemben del ni beseda map; pomembna je vrednost neposredno pred .map().

Trenutna dokumentacija Reacta (React 19.2 ob času pisanja) še vedno uporablja metodo JavaScriptovega polja map() kot standardni način pretvorbe zbirk v elemente JSX. MDN definira Array.prototype.map() kot metodo, ki ustvari novo polje z uporabo povratnega klica na vsakem elementu. Če vrednost, za katero pričakujete, da bo polje, ni bila inicializirana, se še ni naložila ali prihaja iz nepričakovane oblike odgovora API, lahko klic odpove, preden React lahko upodobi seznam. Glejte Vodnik Reacta za upodabljanje seznamov in Referenco MDN za Array.prototype.map().

Ilustrativni scenarij: seznam izdelkov, ki sesede, preden se API konča

To je hipotetičen primer za razlago, ne resničen rezultat testa. Predstavljajte si majhno komponento trgovine, ki pridobi izdelke, ko se komponenta prvič pojavi. Razvijalec napiše:

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

Pri prvem upodabljanju je products undefined, ker useState ni bilo podane začetne vrednosti. Dokumentacija useState v Reactu navaja, da se vrednost stanja pri prvem upodabljanju ujema z začetnim stanjem, ki ga zagotovite. Pridobivanje podatkov (fetch) teče kasneje, zato lahko upodabljanje doseže products.map(...), preden prispe odgovor. Referenca useState v Reactu.

Ilustracija, ustvarjena z umetno inteligenco, ki prikazuje konzolo brskalnika z napako Cannot read properties of undefined reading map v komponenti React.
Ilustracija, ustvarjena z umetno inteligenco, ki kaže na napako JavaScript, ki kaže na upodabljanje seznama, ki kliče .map() na vrednosti undefined.

Korak 1: Natančno poiščite, katera vrednost je undefined

Začnite pri sledi klica (stack trace) in poiščite vrstico, ki vsebuje .map(). V ilustrativni komponenti je ta vrstica products.map(...), zato je products prva vrednost za pregled. V večji komponenti je lahko neuspešen izraz namesto tega data.items.map(), props.users.map() ali response.results.map().

Uporabite razhroščevalnik brskalnika ali začasno beleženje (log) neposredno pred logiko upodabljanja:

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

To loči več napak, ki so v uporabniškem vmesniku videti podobne. Če je vrednost undefined, preverite inicializacijo ali manjkajočo lastnost. Če je null, morda vaš model nalaganja/podatkov izrecno uporablja null. Če je objekt, morda berete napačno raven odgovora API. Če je niz ali število, je pogodba o podatkih navzgor drugačna od tistega, kar pričakuje komponenta.

Ne zamenjajte samodejno vsakega neuspešnega izraza z opcionalnim veriženjem, preden razumete vrednost. To lahko zatre sesutje, hkrati pa pusti napačen tok podatkov na mestu.

Korak 2: Inicializirajte stanje zbirke kot zbirko, če se to ujema z vašim modelom

Za hipotetični seznam izdelkov je prazno polje smiselno začetno stanje, ker se “še ni naloženih izdelkov” lahko varno predstavi kot zbirka z nič elementi:

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

Zdaj lahko prvo upodabljanje zažene products.map(...), ker ima prazno polje metodo map. Ko zahtevek kasneje posodobi stanje, React znova upodobi z vrnjenimi izdelki.

Ilustracija, ustvarjena z umetno inteligenco, ki prikazuje deklaracijo useState v Reactu, inicializirano s praznim poljem.
Ilustracija, ustvarjena z umetno inteligenco, ki prikazuje inicializacijo stanja seznama z useState([]), da ima prvo upodabljanje na voljo polje.

To je močna rešitev, ko je stanje konceptualno vedno polje. Manj je primerno, ko undefined ali null nosita pomenljive informacije, kot je “še ni zahtevano”, medtem ko [] pomeni “zahteva je bila končana in ni rezultatov”. V tem primeru ohranite stanja ločena in izrecno upodobite pogoje nalaganja, napake in praznega stanja.

Korak 3: Preverite obliko odgovora API, preden ga shranite v stanje

Inicializacija popravi le prvo upodabljanje. Komponente ne bo zaščitila, če strežnik kasneje vrne drugačno strukturo. Recimo, da API dejansko vrne:

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

Potem setProducts(data) shrani objekt, ne polja. Verjetna napaka se spremeni v nekaj takega kot products.map is not a function. Pravilna dodelitev bi bila setProducts(data.products), pod pogojem, da je ta lastnost zagotovljeno polje.

Za podatke, ki prečkajo zunanjo mejo, jih validirajte:

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);
  });
Ilustracija, ustvarjena z umetno inteligenco, ki prikazuje komponento React, ki preverja Array.isArray pred klicem map.
Ilustracija, ustvarjena z umetno inteligenco, ki prikazuje zaščito upodabljanja seznama z Array.isArray() pred uporabo .map().

To je pomembno, ker “varen privzeti” ne bi smel spremeniti napačnih produkcijskih podatkov v tiho prazno stran. Če pogodba zahteva polje, je beleženje ali prikaz napake lahko koristnejši kot pretvarjanje vsakega nepričakovanega odgovora v [].

Korak 4: Izberite pravo zaščito pri upodabljanju za podatke, ki lahko upravičeno manjkajo

React podpira običajno pogojno upodabljanje JavaScripta. Uradna dokumentacija prikazuje uporabo if, ternarnih izrazov in && za odločanje, kateri JSX naj se vrne. Vodnik Reacta za pogojno upodabljanje.

Za hipotetično stran izdelkov je pogosto najjasnejši izrecen tok nalaganja in napake:

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

Opcionalno veriženje je tudi veljavno, ko “za zdaj manjka” preprosto ne bi smelo proizvesti nobenega preslikanega rezultata:

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

MDN pojasnjuje, da opcionalno veriženje (?.) prekine izvajanje, ko je vrednost na njegovi levi strani null ali undefined, namesto da bi sprožilo TypeError. Referenca MDN za opcionalno veriženje.

Ilustracija, ustvarjena z umetno inteligenco, ki prikazuje uporabo opcionalnega veriženja pred map v komponenti React.
Ilustracija, ustvarjena z umetno inteligenco, ki prikazuje opcionalno veriženje z users?.map(...) za podatke, ki so lahko začasno undefined.

Omejitev je pomembna: products?.map(...) prepreči to specifično napako dostopa do nullish vrednosti, vendar ne dokazuje, da je products polje. Če products postane objekt, se products?.map še vedno razreši na undefined lastnost in poskus klicanja lahko odpove. Uporabite validacijo sheme ali Array.isArray(), ko je vrsta podatkov sama negotova.

Katero popravilo izbrati?

SituacijaNajboljši prvi korakZakaj
Stanje bi moralo biti vedno seznamuseState([])Prvemu upodabljanju zagotovi pravilno vrsto podatkov.
Manjkajoči podatki imajo pomenljivo stanje nalaganjaPogojno upodabljanjeOhranja “ni naloženo” ločeno od “naloženo, a prazno”.
Oblika API se lahko razlikuje ali je napačnaValidirajte z Array.isArray() ali shemoPrepreči, da bi slabi zunanji podatki neopazno vstopili v stanje komponente.
Prop je po zasnovi opcionalenOpcionalno veriženje ali privzeta vrednost propaIzogiba se razreševanju legitimno odsotne vrednosti.
Napaka se pojavi po refaktoriranjuPreverite imena lastnosti in propovPreimenovano polje lahko nekdanje veljavno polje spremeni v undefined.

Pogosti primeri, ki so videti kot ista napaka

API vrne { items: [...] }, komponenta pa pričakuje polje

Preverite odgovor v zavihku Network in dodelite lastnost polja namesto ovojnega objekta. Ne ugibajte oblike iz starega primera ali vmesnika TypeScript, če se živ odgovor razlikuje.

Nadrejena komponenta pozabi podati prop

To bo spodletelo:

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

// Parent accidentally omits users:
<UserList />

Če izpuščen prop pomeni prazen seznam, privzeta vrednost to pogodbo naredi eksplicitno:

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

Manjka gnezdena lastnost

Pri response.data.items.map(...) lahko odpove katera koli manjkajoča vmesna lastnost. Opcionalno veriženje, kot je response?.data?.items, je uporabno za branje negotovih gnezdenih vrednosti, vendar validirajte končno zbirko, preden jo obravnavate kot polje.

Prvo upodabljanje se zgodi, preden se Effect za pridobivanje podatkov zaključi

Effecti v Reactu tečejo po upodabljanju. Dokumentacija Reacta tudi omenja, da je ročno pridobivanje podatkov znotraj Effectov pogosto v odjemalskih aplikacijah, vendar ima lahko slabosti, kot so slapovi (waterfalls), manjkajoči podatki strežniškega upodabljanja in ročno delo s predpomnjenjem/pogojnimi tekmami. Če uporabljate okvir React, je lahko njegov vgrajeni mehanizem za nalaganje podatkov boljša arhitekturna izbira. Referenca useEffect v Reactu.

Varno končna različica ilustrativne komponente

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

Ta različica namerno razlikuje med “ni naloženo”, “spodletelo”, “prazno” in “ima podatke”. To je bolj besednato kot en sam izraz z opcionalnim veriženjem, vendar uporabniku zagotovi smiseln uporabniški vmesnik za vsako stanje in omogoči vidnost napačnega odgovora API med razhroščevanjem.

Hiter kontrolni seznam, preden štejetе, da je napaka popravljena

  • Identificirajte natančno vrednost neposredno pred .map().
  • Potrdite njeno vrednost in vrsto pri upodabljanju, ki odpove.
  • Inicializirajte stanje seznama z [], ko prazno polje natančno predstavlja začetno stanje.
  • Preverite, ali API vrne polje neposredno ali ga ovije v lastnost objekta.
  • Validirajte zunanje podatke, preden jih shranite v stanje, ko je pogodba pomembna.
  • Uporabite stanje nalaganja, če undefined pomeni “še ni naloženo”.
  • Uporabite opcionalno veriženje, ko je odsotnost legitimna, ne kot nadomestilo za razumevanje slabih podatkov.
  • Po refaktoriranju preverite preimenovane ali izpuščene prope.
  • Dajte upodobljenim elementom seznama stabilne ključe iz podatkov, kot priporoča dokumentacija Reacta za upodabljanje seznamov.

Za hipotetični seznam izdelkov je bil koren vzroka to, da je prvo upodabljanje prejelo undefined, kjer je komponenta takoj pričakovala polje. V resnični aplikaciji lahko isto sporočilo napake povzroči inicializacija stanja, prope, gnezdena lastnost ali podatki API. Najprej popravite pogodbo o podatkih, nato izberite zaščito pri upodabljanju, ki natančno predstavlja, kaj “manjka” pomeni v vašem uporabniškem vmesniku.

Pusti komentar

Kako odpraviti težavo s SSL certifikatom: Unable to Get Local Issuer Certificate v Gitu

Kako odpraviti težavo s SSL certifikatom: Unable to Get Local Issuer Certificate v Gitu

Odpravite napako Git 'unable to get local issuer certificate' z identifikacijo varnostnega ozadja, namestitvijo pravilnega veriga CA in ohranjanjem vklopljene SSL preverjanja.

Kako odpraviti napako omrežnega časovnega prekoraka MongoDB v povezavi Mongoose

Kako odpraviti napako omrežnega časovnega prekoraka MongoDB v povezavi Mongoose

Odpravite napake omrežnega časovnega prekoraka MongoDB v Mongoose z identifikacijo vrste časovnega prekoraka, testiranjem dosegljivosti Atlas ali TCP, popravkom URI in prilagajanjem časovnih omejitev le, ko je to upravičeno.

Kako odpraviti napako Execution Policy Restricted v sistemu Windows PowerShell

Kako odpraviti napako Execution Policy Restricted v sistemu Windows PowerShell

Odpravite napako izvajalne politike Restricted v PowerShellu tako, da preverite obseg in skupinsko politiko, nato izberete RemoteSigned, Unblock-File ali začasno možnost seje.

Kako odpraviti napako npm ERR! code ERESOLVE zaradi konflikta odvisnosti vrstnikov

Kako odpraviti napako npm ERR! code ERESOLVE zaradi konflikta odvisnosti vrstnikov

Odpravite konflikte odvisnosti vrstnikov npm ERESOLVE tako, da identificirate nezdružljiv razpon paketov, uskladite različice, uporabite ukaze npm explain in npm ls ter uporabljate legacy-peer-deps ali force le kot nadzorovane rezervne možnosti.

Kako odpraviti napako pri povezavi Redis na 127.0.0.1:6379

Kako odpraviti napako pri povezavi Redis na 127.0.0.1:6379

Odpravite napake zavrnjene povezave Redis na 127.0.0.1:6379 s preverjanjem strežnika, vrat, Docker omrežja, redis.conf, preverjanja pristnosti in TLS.

Kako odpraviti notranjo napako 500 v strežniških komponentah Next.js

Kako odpraviti notranjo napako 500 v strežniških komponentah Next.js

Odpravite napake 500 v strežniških komponentah Next.js tako, da sledite strežniškim dnevnikom, preverite pridobivanje podatkov in spremenljivke okolja, obravnavate napake ter preverite produkcijsko gradnjo.

Kako odpraviti napako CrashLoopBackOff v Kubernetesu v lokalnem okolju Minikube

Kako odpraviti napako CrashLoopBackOff v Kubernetesu v lokalnem okolju Minikube

Diagnostika in odpravljanje napake CrashLoopBackOff v Kubernetesu v lokalnem okolju Minikube s preverjanjem stanja poda, prejšnjih dnevnikov, razlogov za izhod, sond, konfiguracije, omejitev pomnilnika in zdravja klastra.

Kako popraviti ustavljen pogon Docker Desktop v sistemu Windows 11

Kako popraviti ustavljen pogon Docker Desktop v sistemu Windows 11

Popravite napako 'Engine stopped' v Docker Desktopu na Windows 11 s preverjanjem stanja Dockerja, posodobitvijo in ponovnim zagonom WSL 2, preverjanjem virtualizacije ter uporabo diagnostike pred ponastavitvijo.

Kako odpraviti napako Uncaught ReferenceError: process is not defined v Vite

Kako odpraviti napako Uncaught ReferenceError: process is not defined v Vite

Odpravite napako 'process is not defined' v Vite tako, da zamenjate uporabo process.env v slogu Node.js, pravilno konfigurirate spremenljivke VITE_ in preverite odvisnosti.

Kako odpraviti napako “PyTorch CUDA Out of Memory” med usposabljanjem modela

Kako odpraviti napako “PyTorch CUDA Out of Memory” med usposabljanjem modela

Odpravite napake PyTorch CUDA out-of-memory s praktičnim postopkom: izmerite pomnilnik GPU, zmanjšajte delovni nabor, uporabite AMP in akumulacijo, shranite aktivacije v kontrolne točke in prilagodite dodeljevalnik le, ko je to potrebno.