Miten korjata virhe “Cannot Read Properties of Undefined (Reading map)” Reactissa

React-virhe Cannot read properties of undefined (reading 'map') tarkoittaa, että JavaScript yritti arvioida lauseketta kuten items.map(...), kun items oli undefined. Tärkeä osa ei ole sana map, vaan arvo, joka on välittömästi .map():n edessä.

Nykyinen React-dokumentaatio (React 19.2 kirjoitushetkellä) käyttää edelleen JavaScriptin taulukon map()-metodia standarditapana muuntaa kokoelmia JSX-elementeiksi. MDN määrittelee Array.prototype.map():n menetelmäksi, joka luo uuden taulukon soveltamalla callback-funktiota jokaiseen alkioon. Jos arvo, jonka odotat olevan taulukko, ei ole alustettu, ei ole vielä latautunut tai tulee odottamattomasta API-rakenteesta, kutsu voi epäonnistua ennen kuin React ehtii renderöidä listan. Katso Reactin opas listojen renderöintiin ja MDN:n Array.prototype.map()-viite.

Esimerkkitilanne: tuotelista, joka kaatuu ennen kuin API on valmis

Tämä on hypoteettinen esimerkki selitystä varten, ei todellinen testitulos. Kuvittele pieni verkkokaupan komponentti, joka hakee tuotteet komponentin ensimmäisen näkymän jälkeen. Kehittäjä kirjoittaa:

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

Ensimmäisessä renderöinnissä products on undefined, koska useState:lle ei annettu alkuarvoa. Reactin useState-dokumentaatio toteaa, että tilan arvo ensimmäisessä renderöinnissä vastaa antamaasi alkutilaa. Fetch-suoritus tapahtuu myöhemmin, joten renderöinti voi saavuttaa kohdan products.map(...) ennen kuin vastaus saapuu. React useState -viite.

Tekoälyn luoma kuvitus selaimen konsolista, jossa näkyy virhe Cannot read properties of undefined reading map React-komponentissa.
Tekoälyn luoma kuvitus JavaScript-virheestä, joka osoittaa listan renderöintiin, jossa kutsutaan .map() undefined-arvolle.

Vaihe 1: Etsi tarkasti, mikä arvo on undefined

Aloita pinon jäljityksestä (stack trace) ja etsi rivi, jossa on .map(). Esimerkkikomponentissa tämä rivi on products.map(...), joten products on ensimmäinen arvo, joka tulee tutkia. Suuremmassa komponentissa epäonnistuva lauseke voi olla esimerkiksi data.items.map(), props.users.map() tai response.results.map().

Käytä selaimen debuggeria tai väliaikaista lokitusta välittömästi ennen renderöintilogiikkaa:

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

Tämä erottaa useita virheitä, jotka näyttävät samalta käyttöliittymässä. Jos arvo on undefined, tutki alustusta tai puuttuvaa ominaisuutta. Jos se on null, lataus-/datamallisi saattaa käyttää nolla-arvoa eksplisiittisesti. Jos se on olio, saatat lukea väärää tasoa API-vastauksesta. Jos se on merkkijono tai numero, ylävirran datasopimus eroaa siitä, mitä komponentti odottaa.

Älä automaattisesti korvaa jokaista epäonnistuvaa lauseketta valinnaisella ketjutuksella (optional chaining) ennen kuin ymmärrät arvon. Se voi peittää kaatumisen jättäen virheellisen tietovirran ennalleen.

Vaihe 2: Alusta kokoelman tila kokoelmaksi, jos se vastaa malliasi

Hypoteettiselle tuotelistalle tyhjä taulukko on järkevä alkutila, koska ”ei vielä ladattuja tuotteita” voidaan turvallisesti esittää nollakohtaisena kokoelmana:

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

Nyt ensimmäinen renderöinti voi suorittaa products.map(...), koska tyhjällä taulukolla on map-metodi. Kun pyyntö myöhemmin päivittää tilan, React renderöi uudelleen palautettujen tuotteiden kanssa.

Tekoälyn luoma kuvitus Reactin useState-ilmoituksesta, joka on alustettu tyhjällä taulukolla.
Tekoälyn luoma kuvitus listan tilan alustamisesta komennolla useState([]), jotta ensimmäisessä renderöinnissä on taulukko.

Tämä on vahva korjaus, kun tila on käsitteellisesti aina taulukko. Se on vähemmän sopiva, kun undefined tai null kantaa merkityksellistä tietoa, kuten ”ei vielä pyydetty”, kun taas [] tarkoittaa ”pyyntö valmistui ja tuloksia on nolla”. Tällöin pidä tilat erillään ja renderöi lataus-, virhe- ja tyhjät ehdot eksplisiittisesti.

Vaihe 3: Tarkista API-vastauksen rakenne ennen kuin sijoitat sen tilaan

Alustus korjaa vain ensimmäisen renderöinnin. Se ei suojaa komponenttia, jos palvelin lopulta palauttaa eri rakenteen. Oletetaan, että API palauttaa:

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

Tällöin setProducts(data) tallentaa olion, ei taulukkoa. Todennäköinen virhe muuttuu muotoon products.map is not a function. Oikea sijoitus olisi setProducts(data.products), edellyttäen että tämä ominaisuus on taattu olevan taulukko.

Ulkorajan yli kulkevalle datalle, validoi se:

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);
  });
Tekoälyn luoma kuvitus React-komponentista, joka tarkistaa Array.isArray ennen map-kutsua.
Tekoälyn luoma kuvitus listan renderöinnin suojaamisesta komennolla Array.isArray() ennen .map():n käyttöä.

Tämä on tärkeää, koska ”turvallisen oletuksen” ei pitäisi muuttaa virheellistä tuotantodataa hiljaa tyhjäksi sivuksi. Jos sopimus vaatii taulukkoa, virheen lokitus tai näkyväksi tekeminen voi olla hyödyllisempää kuin muuntaa jokainen odottamaton vastaus muotoon [].

Vaihe 4: Valitse oikea renderöintisuoja datalle, joka voi olla perustellusti puuttuva

React tukee normaalia JavaScriptin ehdollista renderöintiä. Virallisessa dokumentaatiossa näytetään, miten käyttää if-lauseita, ternääri-ilmauksia ja &&-operaattoria päättämään, mitä JSX:tä palautetaan. Reactin ehdollisen renderöinnin opas.

Hypoteettiselle tuotesivulle eksplisiittinen lataus- ja virhekulku on usein selkein:

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

Valinnainen ketjutus on myös kelvollinen, kun ”puuttuu toistaiseksi” pitäisi yksinkertaisesti tuottaa ei-mappattua tulosta:

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

MDN selittää, että valinnainen ketjutus (?.) keskeyttää suorituksen, kun sen vasemmalla puolella oleva arvo on null tai undefined, sen sijaan että heittäisi TypeError-virheen. MDN:n valinnaisen ketjutuksen viite.

Tekoälyn luoma kuvitus valinnaisesta ketjutuksesta ennen map-kutsua React-komponentissa.
Tekoälyn luoma kuvitus valinnaisesta ketjutuksesta users?.map(...) datalle, joka voi tilapäisesti olla undefined.

Rajoitus on tärkeä: products?.map(...) estää tämän tietyn nullish-access-virheen, mutta se ei todista, että products on taulukko. Jos products muuttuu olioksi, products?.map ratkeaa silti undefined-ominaisuudeksi, ja sen kutsu voi epäonnistua. Käytä skeemavaliidaatiota tai Array.isArray(), kun tietotyyppi itsessään on epävarma.

Millaisen korjauksen sinun tulisi valita?

TilanneParas ensimmäinen askelMiksi
Tilan tulisi aina olla listauseState([])Antaa ensimmäiselle renderöinnille oikean tietotyypin.
Puuttuvalla datalla on merkityksellinen lataustilaEhdollinen renderöintiPitää ”ei ladattu” erillään tilasta ”ladattu mutta tyhjä”.
API:n rakenne voi vaihdella tai olla virheellinenValidoi komennolla Array.isArray() tai skeemallaEstää huonoa ulkoista dataa pääsemästä komponentin tilaan huomaamatta.
Prop on suunniteltu valinnaiseksiValinnainen ketjutus tai oletusprop-arvoVälttää perustellusti puuttuvan arvon dereferenssin.
Virhe ilmenee refaktoroinnin jälkeenTarkista ominaisuus- ja prop-nimetUudelleennimetty kenttä voi tehdä aiemmin kelvollisesta taulukosta undefined.

Yleiset tapaukset, jotka näyttävät samalta virheeltä

API palauttaa { items: [...] }, mutta komponentti odottaa taulukkoa

Tutki Network-vastausta ja sijoita taulukko-ominaisuus peittävä olion sijaan. Älä arvaile rakennetta vanhasta esimerkistä tai TypeScript-rajapinnasta, jos live-vastaus eroaa.

Yläkomponentti unohtaa välittää propin

Tämä epäonnistuu:

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

// Parent accidentally omits users:
<UserList />

Jos jätetyn propin tulisi tarkoittaa tyhjää listaa, oletusarvo tekee tästä sopimuksesta eksplisiittisen:

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

Sisäkkäinen ominaisuus puuttuu

Lausekkeessa response.data.items.map(...) mikä tahansa puuttuva välillinen ominaisuus voi aiheuttaa virheen. Valinnainen ketjutus kuten response?.data?.items on hyödyllinen epävarmojen sisäkkäisten arvojen lukemiseen, mutta validoi lopullinen kokoelma ennen kuin käsittelet sitä taulukkona.

Ensimmäinen renderöinti tapahtuu ennen kuin fetch-Effect on valmis

React Effects suoritetaan renderöinnin jälkeen. Reactin dokumentaatio huomauttaa myös, että datan manuaalinen hakeminen Effectsien sisällä on yleistä asiakaspuolen sovelluksissa, mutta sillä voi olla haittoja kuten vesiputoukset (waterfalls), puuttuva palvelinpuolen renderöity data ja manuaalinen välimuistin/kilpailutilanteiden hallinta. Jos käytät React-kehystä, sen sisäänrakennettu datan latausmekanismi voi olla parempi arkkitehtoninen valinta. React useEffect -viite.

Turvallisempi lopullinen versio esimerkkikomponentista

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

Tämä versio erottaa tarkoituksellisesti tilat ”ei ladattu”, ”epäonnistui”, ”tyhjä” ja ”dataa olemassa”. Se on puhekielisempi kuin yksittäinen valinnainen ketjutuslauseke, mutta se antaa käyttäjälle merkityksellisen käyttöliittymän jokaiselle tilalle ja tekee virheellisestä API-vastauksesta näkyvän debuggauksen aikana.

Pikalistatarkistus ennen kuin harkitset virheen korjatuksi

  • Tunnista tarkka arvo välittömästi .map():n edessä.
  • Varmista sen arvo ja tyyppi epäonnistuvassa renderöinnissä.
  • Alusta listan tila arvolla [], kun tyhjä taulukko kuvaa alkutilaa tarkasti.
  • Tarkista, palauttaako API taulukon suoraan vai kääriikö sen olion ominaisuuteen.
  • Validoi ulkoinen data ennen sen tallentamista tilaan, kun sopimus on tärkeä.
  • Käytä lataustilaa, jos undefined tarkoittaa ”ei vielä ladattu”.
  • Käytä valinnaista ketjutusta, kun puuttuminen on perusteltua, ei korvikkeena huonon datan ymmärtämiselle.
  • Tarkista uudelleennimettyjä tai jätettyjä proppeja refaktorointien jälkeen.
  • Anna renderöidyille listakohteille vakaat avaimet datasta, kuten Reactin listojen renderöintidokumentaatio suosittelee.

Hypoteettiselle tuotelistalle juurisyy oli se, että ensimmäinen renderöinti sai undefined-arvon, jossa komponentti odotti välittömästi taulukkoa. Todellisessa sovelluksessa sama virheilmoitus voi johtua tilan alustuksesta, proppeista, sisäkkäisistä ominaisuuksista tai API-datasta. Korjaa datasopimus ensin, valitse sitten renderöintisuoja, joka kuvaa tarkasti, mitä ”puuttuminen” tarkoittaa käyttöliittymässäsi.

Jätä kommentti

Kuinka korjata "ENOSPC: Järjestelmän raja tiedostojen tarkkailijoille saavutettu" Linuxissa

Kuinka korjata "ENOSPC: Järjestelmän raja tiedostojen tarkkailijoille saavutettu" Linuxissa

Korjaa Linux ENOSPC -tiedostojen tarkkailijan virheet tarkistamalla inotify-rajoitukset, etsimällä tarkkailijapainotteisia prosesseja, nostamalla rajoituksia turvallisesti ja tekemällä muutoksista pysyviä.

Kuinka korjata "Tailwind CSS Styles Not Update" -ongelma Vite React -sovelluksessa

Kuinka korjata "Tailwind CSS Styles Not Update" -ongelma Vite React -sovelluksessa

Korjaa Tailwind CSS -tyylien päivittymättömyys Vite Reactissa tarkistamalla Tailwind v4 -asetukset, CSS-tuonnit, lähteen tunnistus, dynaamiset luokat, HMR ja vanhentuneet välimuistit.

Kuinka korjata ModuleNotFoundError: Ei moduulia nimeltä 'pip' Python 3:ssa

Kuinka korjata ModuleNotFoundError: Ei moduulia nimeltä 'pip' Python 3:ssa

Korjaa Python 3:n ModuleNotFoundError-virhe pip-funktiolle Windowsissa, macOS:ssä ja Linuxissa ensurepip-komennolla, käyttöjärjestelmäpaketeilla, virtuaaliympäristöillä ja tulkkitarkistuksilla.

Kuinka korjata "Käyttöoikeus evätty (julkinen avain)" GitHub SSH:ssa

Kuinka korjata "Käyttöoikeus evätty (julkinen avain)" GitHub SSH:ssa

Korjaa GitHub SSH -käyttöoikeus evätty (julkinen avain) -ongelma tarkistamalla isäntä, aktiivinen SSH-avain, GitHub-tili, kertakirjautumisen valtuutus, etä-URL-osoite ja portin 22 käyttöoikeus.

Kuinka korjata "Git Push Rejected: Non-Fast-Forward" menettämättä muutoksia

Kuinka korjata "Git Push Rejected: Non-Fast-Forward" menettämättä muutoksia

Korjaa Gitin ei-pikakelausvirhe turvallisesti. Suojaa paikallinen työ, nouda etäcommitit, valitse yhdistäminen tai uudelleenpohjustaminen, ratkaise ristiriidat ja puske muutosten menettämättä.

Kuinka korjata "Nginx 502 Bad Gateway" -virhe, kun välityspalvelimena käytetään Node.js:ää

Kuinka korjata "Nginx 502 Bad Gateway" -virhe, kun välityspalvelimena käytetään Node.js:ää

Korjaa Nginx 502 Bad Gateway -virheet Node.js:n avulla ylävirran puolella tarkistamalla sovellusportti, NGINX-lokit, proxy_pass-osoite, säilöverkko, aikakatkaisut ja uudelleenlataus.

Kuinka korjata "Type 'null' ei ole määritettävissä tyypille" TypeScriptissä

Kuinka korjata "Type 'null' ei ole määritettävissä tyypille" TypeScriptissä

Korjaa TypeScriptin virhe ”Type 'null' ei ole määritettävissä tyypille” yhdistämistyypeillä, rajaamisella, oletusarvoilla ja turvallisilla väitteillä strictNullChecksin avulla.

Kuinka korjata "Prisma Client has not been generated yet" -virhe

Kuinka korjata "Prisma Client has not been generated yet" -virhe

Korjaa Prisma Clientin luontivirhe tarkistamalla generaattori, skeema, tulostepolku, importit, versiot, monorepo-asetukset ja käyttöönoton build-vaiheet.

Kuinka korjata "ERR_MODULE_NOT_FOUND" Node.js ESM -tuonneissa

Kuinka korjata "ERR_MODULE_NOT_FOUND" Node.js ESM -tuonneissa

Korjaa Node.js ERR_MODULE_NOT_FOUND ESM:ssä tarkistamalla tuontipolut, tiedostopäätteet, pakettien asennuksen, viennit, ESM-tilan ja puhtaat asennukset.

Kuinka korjata SSL-varmenneongelma: Paikallisen myöntäjän varmenteen haku epäonnistui Gitissä

Kuinka korjata SSL-varmenneongelma: Paikallisen myöntäjän varmenteen haku epäonnistui Gitissä

Korjaa Gitin virhe "paikallisen myöntäjän varmenteen haku epäonnistui" tunnistamalla luottamuksen taustajärjestelmä, asentamalla oikea CA-ketju ja pitämällä SSL-varmenteiden tarkistus päällä.