Hem
» Grundläggande kunskap
»
Så här åtgärdar du felet “Cannot Read Properties of Undefined (Reading map)” i React
Så här åtgärdar du felet “Cannot Read Properties of Undefined (Reading map)” i React
React-felet Cannot read properties of undefined (reading 'map') innebär att JavaScript försökte utvärdera något som items.map(...) medan items var undefined. Det viktiga är inte ordet map; det är värdet omedelbart före .map().
Den aktuella React-dokumentationen (React 19.2 vid tidpunkten för skrivandet) använder fortfarande JavaScripts arraymetod map() som standardmetod för att omvandla samlingar till JSX-element. MDN definierar Array.prototype.map() som en metod som skapar en ny array genom att tillämpa en callback på varje element. Om värdet du förväntar dig ska vara en array inte har initierats, inte har laddats än eller kommer från en oväntad API-struktur, kan anropet misslyckas innan React hinner rendera listan. Se React:s guide för rendering av listor och MDN:s referens för Array.prototype.map().
Illustrativt scenario: en produktlista som kraschar innan API:t är klart
Detta är ett hypotetiskt exempel för förklaring, inte ett verkligt testresultat. Föreställ dig en liten butikskomponent som hämtar produkter efter att komponenten först visas. Utvecklaren skriver:
Vid den första renderingen är productsundefined eftersom inget initialvärde skickades till useState. Reacts dokumentation för useState anger att state-värdet vid den första renderingen motsvarar det initiala tillstånd du tillhandahåller. Hämtningen körs efteråt, så renderingen kan nå products.map(...) innan svaret anländer. React useState-referens.
AI-genererad illustration av JavaScript-felet som pekar på en listrendering som anropar .map() på ett odefinierat värde.
Steg 1: Hitta exakt vilket värde som är odefinierat
Börja vid stackspåret och hitta raden som innehåller .map(). I den illustrativa komponenten är den raden products.map(...), så products är det första värdet att inspektera. I en större komponent kan det misslyckade uttrycket istället vara data.items.map(), props.users.map() eller response.results.map().
Använd webbläsarens felsökare eller en tillfällig loggning omedelbart innan renderingslogiken:
Detta skiljer på flera buggar som ser likadana ut i UI:t. Om värdet är undefined, undersök initiering eller en saknad egenskap. Om det är null, kan din laddnings-/datamodell uttryckligen använda null. Om det är ett objekt, läser du kanske fel nivå av ett API-svar. Om det är en sträng eller ett nummer, skiljer sig uppströms datakontrakt från vad komponenten förväntar sig.
Ersätt inte automatiskt varje misslyckat uttryck med valfri kedjning (optional chaining) innan du förstår värdet. Det kan undertrycka kraschen men lämna felaktigt dataflöde kvar.
Steg 2: Initiera collectionsstate som en collection när det stämmer med din modell
För den hypotetiska produktlistan är en tom array ett rimligt initialtillstånd eftersom “inga produkter har laddats än” säkert kan representeras som en samling med noll objekt:
const [products, setProducts] = useState([]);
Nu kan den första renderingen köra products.map(...) eftersom en tom array har en map-metod. När begäran senare uppdaterar state:n, renderar React igen med de returnerade produkterna.
AI-genererad illustration av att initiera liststate med useState([]) så att den första renderingen har en array.
Detta är en stark lösning när state:n konceptuellt alltid är en array. Det är mindre lämpligt när undefined eller null bär på meningsfull information, som “inte begärd än”, medan [] betyder “begäran är klar och det finns noll resultat”. I det fallet, håll tillstånden distinkta och rendera laddnings-, fel- och tomma tillstånd explicit.
Steg 3: Verifiera API-svarets struktur innan du lägger det i state
Initiering löser bara den första renderingen. Den skyddar inte komponenten om servern till slut returnerar en annan struktur. Antag att API:t faktiskt returnerar:
Då lagrar setProducts(data) ett objekt, inte en array. Det troliga felet ändras till något som products.map is not a function. Den korrekta tilldelningen skulle vara setProducts(data.products), förutsatt att den egenskapen garanterat är en array.
För data som korsar en extern gräns, validera den:
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-genererad illustration av att skydda en listrendering med Array.isArray() innan .map() används.
Detta är viktigt eftersom en “säker standard” inte ska förvandla felaktig produktionsdata till en tyst tom sida. Om en array krävs av kontraktet, kan loggning eller att synliggöra ett fel vara mer användbart än att konvertera varje oväntat svar till [].
Steg 4: Välj rätt renderingskontroll för data som legitimt kan saknas
React stöder vanlig JavaScript-villkorlig rendering. De officiella dokumenten visar användning av if, ternära uttryck och && för att bestämma vilken JSX som ska returneras. React guide för villkorlig rendering.
För den hypotetiska produktsidan är ett explicit flöde för laddning och fel ofta det tydligaste:
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>
);
Valfri kedjning är också giltig när “saknas just nu” helt enkelt ska producera inget mappat resultat:
MDN förklarar att valfri kedjning (?.) avbryts (short-circuits) när värdet till vänster om den är null eller undefined istället för att kasta ett TypeError. MDN referens för valfri kedjning.
AI-genererad illustration av valfri kedjning med users?.map(...) för data som tillfälligt kan vara odefinierad.
Begränsningen är viktig: products?.map(...) förhindrar detta specifika nullish-access-fel, men det bevisar inte att products är en array. Om products blir ett objekt, löses products?.map fortfarande till en odefinierad egenskap och att försöka anropa den kan misslyckas. Använd schemavalidering eller Array.isArray() när datatypen i sig är osäker.
Vilken lösning bör du välja?
Situation
Bästa första drag
Varför
State bör alltid vara en lista
useState([])
Ger den första renderingen rätt datatyp.
Saknad data har ett meningsfullt laddningstillstånd
Villkorlig rendering
Håller “inte laddad” separat från “laddad men tom”.
API-strukturen kan variera eller vara felaktig
Validera med Array.isArray() eller ett schema
Förhindrar att dålig extern data kommer in i komponentstate utan att upptäckas.
Prop är valfri per design
Valfri kedjning eller ett standardprop-värde
Undviker att dereferera ett legitimt frånvarande värde.
Fel uppstår efter en refactor
Kontrollera egenskaps- och propnamn
Ett omdöpt fält kan göra att en tidigare giltig array blir undefined.
Vanliga fall som ser ut som samma fel
API:t returnerar { items: [...] }, men komponenten förväntar sig en array
Inspektera nätverkssvaret och tilldela arrayegenskapen istället för wrapperobjektet. Gissa inte strukturen från ett gammalt exempel eller TypeScript-gränssnitt om det levande svaret skiljer sig.
Med response.data.items.map(...) kan varje saknad mellanliggande egenskap misslyckas. Valfri kedjning som response?.data?.items är användbar för att läsa osäkra nästlade värden, men validera den slutliga samlingen innan du behandlar den som en array.
Den första renderingen sker innan en fetch Effect är klar
React Effects körs efter rendering. Reacts dokumentation noterar också att manuell hämtning av data inuti Effects är vanligt i klientapplikationer men kan ha nackdelar som vattenfall, saknad serverrenderad data och manuellt arbete med cachning/tävlingsvillkor. Om du använder ett React-ramverk, kan dess inbyggda mekanism för datainläsning vara ett bättre arkitektoniskt val. React useEffect-referens.
En säkrare slutversion av den illustrativa komponenten
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>
);
}
Denna version skiljer avsiktligt på “inte laddad”, “misslyckad”, “tom” och “har data”. Det är mer omfattande än ett enda valfri-kedjeuttryck, men det ger användaren ett meningsfullt UI för varje tillstånd och gör ett felaktigt API-svar synligt under felsökning.
Snabb checklista innan du anser att buggen är åtgärdad
Identifiera det exakta värdet omedelbart före .map().
Bekräfta dess värde och typ vid den rendering som misslyckas.
Initiera liststate med [] när en tom array korrekt representerar initialtillståndet.
Kontrollera om API:t returnerar en array direkt eller omsluter den i ett objekt.
Validera extern data innan du lagrar den i state när kontraktet är viktigt.
Använd ett laddningstillstånd om undefined betyder “inte laddad än”.
Använd valfri kedjning när frånvaro är legitim, inte som en ersättning för att förstå dålig data.
Kontrollera omdöpta eller utelämnade props efter refactors.
Ge renderade listobjekt stabila nycklar från datan, enligt rekommendationen i Reacts dokumentation för listrendering.
För den hypotetiska produktlistan var grundorsaken att den första renderingen fick undefined där komponenten omedelbart förväntade sig en array. I en verklig applikation kan samma felmeddelande komma från state-initiering, props, nästlade egenskaper eller API-data. Åtgärda datakontraktet först, välj sedan en renderingskontroll som korrekt representerar vad “saknas” betyder i ditt UI.