Domov
» Základné znalosti
»
Ako opraviť chybu „Cannot read properties of undefined (reading 'map')“ v React
Ako opraviť chybu „Cannot read properties of undefined (reading 'map')“ v React
Chyba React Cannot read properties of undefined (reading 'map') znamená, že JavaScript sa pokúsil vyhodnotiť niečo ako items.map(...), pričom items bolo undefined. Dôležitou časťou nie je slovo map; je to hodnota bezprostredne pred .map().
Aktuálna dokumentácia React (React 19.2 v čase písania) stále používa JavaScriptovú metódu poľa map() ako štandardný spôsob prevodu kolekcií na JSX prvky. MDN definuje Array.prototype.map() ako metódu, ktorá vytvára nové pole aplikáciou callbacku na každý prvok. Ak hodnota, ktorú očakávate ako pole, nebola inicializovaná, ešte sa nenačítala alebo pochádza z neočakávanej štruktúry API, volanie môže zlyhať skôr, než React dokáže vykresliť zoznam. Pozrite si sprievodcu React vykresľovaním zoznamov a referenciu MDN pre Array.prototype.map().
Ilustratívny scenár: zoznam produktov, ktorý zlyhá pred dokončením požiadavky na API
Toto je hypotetický príklad na vysvetlenie, nie skutočný výsledok testu. Predstavte si malú komponentu obchodu, ktorá načítava produkty po prvom zobrazení komponenty. Vývojár napíše:
Pri prvom vykreslení je productsundefined, pretože do useState nebola odovzdaná žiadna počiatočná hodnota. Dokumentácia useState v React uvádza, že hodnota stavu pri prvom vykreslení zodpovedá počiatočnému stavu, ktorý poskytnete. Požiadavka fetch sa spustí až následne, takže vykreslenie môže dosiahnuť products.map(...) skôr, než príde odpoveď. Referencia React useState.
Ilustrácia generovaná AI zobrazujúca chybu JavaScriptu ukazujúcu na vykreslenie zoznamu, ktoré volá .map() na nedefinovanej hodnote.
Krok 1: Nájdite presne tú hodnotu, ktorá je nedefinovaná
Začnite pri zásobníku volaní (stack trace) a nájdite riadok obsahujúci .map(). V ilustračnej komponente je týmto riadkom products.map(...), takže products je prvá hodnota na preskúmanie. Vo väčšej komponente môže byť zlyhávajúcim výrazom namiesto toho data.items.map(), props.users.map() alebo response.results.map().
Použite debugger prehliadača alebo dočasný log bezprostredne pred logikou vykresľovania:
Tým rozlíšite niekoľko chýb, ktoré vyzerajú v používateľskom rozhraní podobne. Ak je hodnota undefined, preskúmajte inicializáciu alebo chýbajúcu vlastnosť. Ak je null, váš model načítania/dát môže explicitne používať null. Ak je to objekt, možno čítate nesprávnu úroveň odpovede z API. Ak je to reťazec alebo číslo, dátová zmluva od zdroja sa líši od toho, čo komponenta očakáva.
Neautomaticky nenahrádzajte každý zlyhávajúci výraz voliteľným reťazením (optional chaining) skôr, než pochopíte hodnotu. To môže potlačiť pád, ale ponechať nesprávny tok dát na mieste.
Krok 2: Inicializujte stav kolekcie ako kolekciu, ak to zodpovedá vášmu modelu
Pre hypotetický zoznam produktov je prázdne pole rozumným počiatočným stavom, pretože „žiadne produkty ešte načítané“ môže byť bezpečne reprezentované ako kolekcia s nulovým počtom položiek:
const [products, setProducts] = useState([]);
Teraz môže prvé vykreslenie spustiť products.map(...), pretože prázdne pole má metódu map. Keď požiadavka neskôr aktualizuje stav, React vykreslí znova s vrátenými produktmi.
Ilustrácia generovaná AI zobrazujúca inicializáciu stavu zoznamu pomocou useState([]), aby prvé vykreslenie malo pole.
Toto je silné riešenie, keď je stav konceptuálne vždy pole. Je menej vhodné, keď undefined alebo null nesie významnú informáciu, napríklad „zatiaľ nevyžiadané“, zatiaľ čo [] znamená „požiadavka dokončená a sú nula výsledkov“. V takom prípade udržujte stavy odlišné a explicitne vykresľujte podmienky načítavania, chyby a prázdneho stavu.
Krok 3: Overte štruktúru odpovede API pred uložením do stavu
Inicializácia rieši iba prvé vykreslenie. Neochráni komponentu, ak server nakoniec vráti inú štruktúru. Predpokladajme, že API skutočne vráti:
Potom setProducts(data) uloží objekt, nie pole. Pravdepodobná chyba sa zmení na niečo ako products.map is not a function. Správne priradenie by bolo setProducts(data.products), za predpokladu, že táto vlastnosť je zaručene pole.
Pre dáta prechádzajúce vonkajšou hranicou ich validujte:
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);
});
Ilustrácia generovaná AI zobrazujúca ochranu vykreslenia zoznamu pomocou Array.isArray() pred použitím .map().
To je dôležité, pretože „bezpečná predvolená hodnota“ by nemala meniť poškodené produkčné dáta na ticho prázdnu stránku. Ak je pole vyžadované zmluvou, logovanie alebo zobrazenie chyby môže byť užitočnejšie než konverzia každej neočakávanej odpovede na [].
Krok 4: Vyberte správnu ochrannú mechanizmus vykresľovania pre dáta, ktoré môžu legitímne chýbať
React podporuje bežné JavaScriptové podmienené vykresľovanie. Oficiálna dokumentácia ukazuje použitie if, ternárnych výrazov a && na rozhodnutie, aký JSX vrátiť. Sprievodca React podmieneným vykresľovaním.
Pre hypotetickú stránku produktov je explicitný tok načítavania a chyby často najjasnejší:
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>
);
Voliteľné reťazenie je tiež platné, keď „zatiaľ chýba“ by malo jednoducho vyprodukovať žiadny mapovaný výsledok:
MDN vysvetľuje, že voliteľné reťazenie (?.) sa skratuje (short-circuits), keď je hodnota na jeho ľavej strane null alebo undefined, namiesto toho, aby vyhodila TypeError. Referencia MDN pre voliteľné reťazenie.
Ilustrácia generovaná AI zobrazujúca voliteľné reťazenie s users?.map(...) pre dáta, ktoré môžu byť dočasne nedefinované.
Obmedzenie je dôležité: products?.map(...) zabraňuje tejto konkrétnej chybe prístupu k nullish hodnote, ale nedokazuje, že products je pole. Ak sa products stane objektom, products?.map sa stále vyhodnotí na nedefinovanú vlastnosť a pokus o jej volanie môže zlyhať. Použite validáciu schémy alebo Array.isArray(), keď je dátový typ sám o sebe neistý.
Ktoré riešenie by ste mali zvoliť?
Situácia
Najlepšie prvé opatrenie
Prečo
Stav by mal byť vždy zoznam
useState([])
Poskytuje prvému vykresleniu správny dátový typ.
Chýbajúce dáta majú významný stav načítavania
Podmienené vykresľovanie
Udržuje „nezačítané“ oddelené od „načítané, ale prázdne“.
Štruktúra API sa môže meniť alebo byť poškodená
Validujte pomocou Array.isArray() alebo schémy
Zabraňuje vstupu zlých vonkajších dát do stavu komponenty bez povšimnutia.
Prop je z návrhu voliteľný
Voliteľné reťazenie alebo predvolená hodnota propu
Vyhnite sa dereferencii legitímne chýbajúcej hodnoty.
Chyba sa objaví po refactoringu
Skontrolujte názvy vlastností a propov
Premenované pole môže spôsobiť, že kedysi platné pole sa stane nedefinovaným.
Bežné prípady, ktoré vyzerajú ako tá istá chyba
API vracia { items: [...] }, ale komponenta očakáva pole
Preskúmajte odpoveď v sieti (Network) a priraďte vlastnosť poľa, nie obalový objekt. Nehádajte štruktúru zo starého príkladu alebo rozhrania TypeScript, ak sa živá odpoveď líši.
Pri response.data.items.map(...) môže zlyhať akákoľvek chýbajúca medzivlastnosť. Voliteľné reťazenie ako response?.data?.items je užitočné na čítanie neistých vnorených hodnôt, ale pred spracovaním ako pole validujte konečnú kolekciu.
Prvé vykreslenie nastane skôr, než sa dokončí Effect na načítanie dát
React Effects sa spúšťajú po vykreslení. Dokumentácia React tiež uvádza, že manuálne načítanie dát vnútri Effects je bežné v klientskych aplikáciách, ale môže mať nevýhody, ako sú vodopády požiadaviek, chýbajúce dáta vykreslené na serveri a manuálna práca s cache/race conditions. Ak používate framework React, jeho vstavaný mechanizmus načítavania dát môže byť lepšou architektonickou voľbou. Referencia React useEffect.
Bezpečnejšia finálna verzia ilustračnej komponenty
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áto verzia zámerne rozlišuje „nezačítané“, „zlyhané“, „prázdne“ a „má dáta“. Je to verbosejšie než jeden výraz s voliteľným reťazením, ale poskytuje používateľovi zmysluplné UI pre každý stav a robí poškodenú odpoveď API viditeľnú počas ladenia.
Rýchly kontrolný zoznam pred tým, ako považujete chybu za opravenú
Identifikujte presnú hodnotu bezprostredne pred .map().
Potvrďte jej hodnotu a typ pri vykreslení, ktoré zlyhá.
Inicializujte stav zoznamu pomocou [], keď prázdne pole presne reprezentuje počiatočný stav.
Skontrolujte, či API vracia pole priamo, alebo ho obaľuje vo vlastnosti objektu.
Validujte vonkajšie dáta pred uložením do stavu, keď na zmluve záleží.
Použite stav načítavania, ak undefined znamená „zatiaľ nezačítané“.
Použite voliteľné reťazenie, keď je neprítomnosť legitímna, nie ako náhradu za pochopenie zlých dát.
Skontrolujte premenované alebo vynechané propy po refaktoringu.
Dajte vykresleným položkám zoznamu stabilné kľúče z dát, ako odporúča dokumentácia React pre vykresľovanie zoznamov.
Pre hypotetický zoznam produktov bola príčinou koreňa to, že prvé vykreslenie dostalo undefined tam, kde komponenta okamžite očakávala pole. V reálnej aplikácii môže rovnaká chybová správa pochádzať z inicializácie stavu, propov, vnorených vlastností alebo dát z API. Najprv opravte dátovú zmluvu, potom vyberte ochranný mechanizmus vykresľovania, ktorý presne reprezentuje, čo „chýbajúce“ znamená vo vašom UI.