Jak opravit chybu „Cannot read properties of undefined (reading 'map')“ v Reactu

Chyba Reactu Cannot read properties of undefined (reading 'map') znamená, že se JavaScript pokusil vyhodnotit něco jako items.map(...), zatímco items bylo undefined. Důležitá není samotná funkce map, ale hodnota bezprostředně před .map().

Aktuální dokumentace Reactu (React 19.2 v době psaní tohoto textu) stále používá metodu JavaScriptu map() pro pole jako standardní způsob, jak převést kolekce na JSX elementy. MDN definuje Array.prototype.map() jako metodu, která vytváří nové pole aplikací callbacku na každý prvek. Pokud hodnota, kterou očekáváte jako pole, nebyla inicializována, ještě se nenačetla nebo pochází z neočekávané struktury odpovědi API, může volání selhat dříve, než React stihne vykreslit seznam. Podívejte se na průvodce vykreslováním seznamů v Reactu a na referenci MDN pro Array.prototype.map().

Ilustrativní scénář: seznam produktů, který spadne, než se dokončí načtení z API

Toto je hypotetický příklad pro vysvětlení, nikoliv výsledek reálného testu. Představte si malou komponentu obchodu, která načítá produkty poté, co se komponenta poprvé objeví. Vývojář napíš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>
  );
}

Při prvním vykreslení je products undefined, protože funkci useState nebyla předána žádná počáteční hodnota. Dokumentace Reactu k useState uvádí, že hodnota stavu při prvním vykreslení odpovídá počátečnímu stavu, který poskytnete. Načítání dat probíhá až následně, takže vykreslování může narazit na products.map(...) dříve, než dorazí odpověď. Reference React useState.

Ilustrace vygenerovaná AI zobrazující konzoli prohlížeče s chybou Cannot read properties of undefined reading map v komponentě React.
Ilustrace vygenerovaná AI zobrazující chybu JavaScriptu ukazující na vykreslení seznamu, které volá .map() na nedefinované hodnotě.

Krok 1: Najděte přesně, která hodnota je nedefinovaná

Začněte u stack trace a najděte řádek obsahující .map(). V ilustrativní komponentě je tímto řádkem products.map(...), takže products je první hodnota, kterou je třeba prozkoumat. Ve větší komponentě může být selhávající výraz místo toho data.items.map(), props.users.map() nebo response.results.map().

Použijte debugger prohlížeče nebo dočasný log bezprostředně před logikou vykreslování:

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

Tím oddělíte několik chyb, které vypadají v UI podobně. Pokud je hodnota undefined, zkoumejte inicializaci nebo chybějící vlastnost. Pokud je null, váš model načítání/dat může explicitně používat null. Pokud je to objekt, možná čtete špatnou úroveň odpovědi API. Pokud je to řetězec nebo číslo, datová smlouva od zdroje se liší od toho, co komponenta očekává.

Neautomaticky nahrazujte každý selhávající výraz volitelným řetězením (optional chaining), dokud nepochopíte danou hodnotu. To může potlačit pád, ale ponechat nesprávný tok dat na místě.

Krok 2: Inicializujte stav kolekce jako kolekci, pokud to odpovídá vašemu modelu

Pro hypotetický seznam produktů je prázdné pole rozumným počátečním stavem, protože „žádné produkty ještě nenačteny“ lze bezpečně reprezentovat jako kolekci s nulovým počtem položek:

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

Nyní může první vykreslení spustit products.map(...), protože prázdné pole má metodu map. Když později požadavek aktualizuje stav, React znovu vykreslí s vrácenými produkty.

Ilustrace vygenerovaná AI zobrazující deklaraci useState v Reactu inicializovanou prázdným polem.
Ilustrace vygenerovaná AI zobrazující inicializaci stavu seznamu pomocí useState([]), aby první vykreslení mělo pole.

Toto je silné řešení, když je stav konceptuálně vždy pole. Je méně vhodné, když undefined nebo null nese smysluplnou informaci, například „ještě nevyžádáno“, zatímco [] znamená „požadavek dokončen a jsou nula výsledků“. V takovém případě udržujte stavy odlišné a explicitně vykreslujte podmínky načítání, chyby a prázdného stavu.

Krok 3: Ověřte tvar odpovědi API před uložením do stavu

Inicializace řeší pouze první vykreslení. Neochrání komponentu, pokud server nakonec vrátí jinou strukturu. Předpokládejme, že API ve skutečnosti vrací:

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

Pak setProducts(data) uloží objekt, nikoli pole. Pravděpodobná chyba se změní na něco jako products.map is not a function. Správné přiřazení by bylo setProducts(data.products), za předpokladu, že tato vlastnost je zaručeně pole.

Pro data přicházející z vnější hranice je 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);
  });
Ilustrace vygenerovaná AI zobrazující komponentu Reactu kontrolující Array.isArray před voláním map.
Ilustrace vygenerovaná AI zobrazující ochranu vykreslení seznamu pomocí Array.isArray() před použitím .map().

To je důležité, protože „bezpečná výchozí hodnota“ by neměla proměnit špatná produkční data na tiše prázdnou stránku. Pokud je pole vyžadováno smlouvou, logování nebo zobrazení chyby může být užitečnější než převod každé neočekávané odpovědi na [].

Krok 4: Vyberte správnou ochranu při vykreslování pro data, která mohou oprávněně chybět

React podporuje běžné podmíněné vykreslování v JavaScriptu. Oficiální dokumentace ukazuje použití if, ternárních výrazů a && k rozhodnutí, jaký JSX vrátit. Průvodce podmíněným vykreslováním v Reactu.

Pro hypotetickou stránku produktů je explicitní tok načítání a chyby často nejjasnější:

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

Volitelné řetězení je také platné, když „chybí zatím“ by mělo jednoduše vyprodukovat žádný namapovaný výsledek:

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

MDN vysvětluje, že volitelné řetězení (?.) přeruší vyhodnocování, pokud je hodnota vlevo od něj null nebo undefined, místo aby vyhodilo TypeError. Reference MDN pro volitelné řetězení.

Ilustrace vygenerovaná AI zobrazující použití volitelného řetězení před map v komponentě React.
Ilustrace vygenerovaná AI zobrazující volitelné řetězení s users?.map(...) pro data, která mohou být dočasně nedefinovaná.

Omezení je důležité: products?.map(...) zabraňuje této konkrétní chybě přístupu k nullish hodnotě, ale nedokazuje, že products je pole. Pokud se products stane objektem, products?.map stále vyhodnotí na nedefinovanou vlastnost a pokus o její volání může selhat. Použijte validaci schématu nebo Array.isArray(), pokud je datový typ sám o sobě nejistý.

Které řešení byste měli zvolit?

SituaceNejlepší první krokProč
Stav by měl být vždy seznamuseState([])Dá prvnímu vykreslení správný datový typ.
Chybějící data mají smysluplný stav načítáníPodmíněné vykreslováníUdržuje „nenačteno“ odděleně od „načteno, ale prázdné“.
Tvar API se může lišit nebo být chybnýValidace pomocí Array.isArray() nebo schématuZabraňuje vstupu špatných externích dat do stavu komponenty bez povšimnutí.
Prop je záměrně volitelnýVolitelné řetězení nebo výchozí hodnota propuVyhýbá se dereferencování oprávněně chybějící hodnoty.
Chyba se objeví po refaktoringuZkontrolujte názvy vlastností a propůPřejmenované pole může způsobit, že dříve platné pole se stane nedefinovaným.

Běžné případy, které vypadají jako stejná chyba

API vrací { items: [...] }, ale komponenta očekává pole

Zkontrolujte odpověď v síti a přiřaďte vlastnost pole, nikoli obalující objekt. Nehádejte tvar ze starého příkladu nebo TypeScript rozhraní, pokud se živá odpověď liší.

Rodičovská komponenta zapomene předat prop

Toto selže:

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

// Parent accidentally omits users:
<UserList />

Pokud by vynechaný prop měl znamenat prázdný seznam, výchozí hodnota tuto smlouvu explicitně vyjádří:

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

Chybí vnořená vlastnost

Při response.data.items.map(...) může selhat jakákoli chybějící mezivlastnost. Volitelné řetězení jako response?.data?.items je užitečné pro čtení nejistých vnořených hodnot, ale před zpracováním jako pole ověřte konečnou kolekci.

První vykreslení proběhne před dokončením Effectu pro načtení dat

React Effects se spouštějí po vykreslení. Dokumentace Reactu také uvádí, že ruční načítání dat uvnitř Effectů je běžné v klientských aplikacích, ale může mít nevýhody, jako jsou vodopády požadavků, chybějící data vykreslená na serveru a ruční práce s cache a race conditions. Pokud používáte framework postavený na Reactu, jeho vestavěný mechanismus načítání dat může být lepší architektonickou volbou. Reference React useEffect.

Bezpečnější finální verze ilustrativní 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>
  );
}

Tato verze záměrně rozlišuje „nenačteno“, „selhalo“, „prázdné“ a „má data“. Je to obsáhlejší než jeden výraz s volitelným řetězením, ale poskytuje uživateli smysluplné UI pro každý stav a činí chybnou odpověď API viditelnou během ladění.

Rychlý kontrolní seznam, než budete považovat chybu za opravenou

  • Identifikujte přesnou hodnotu bezprostředně před .map().
  • Potvrďte její hodnotu a typ při selhávajícím vykreslení.
  • Inicializujte stav seznamu pomocí [], pokud prázdné pole přesně reprezentuje počáteční stav.
  • Zkontrolujte, zda API vrací pole přímo, nebo ho obaluje ve vlastnosti objektu.
  • Validujte externí data před uložením do stavu, pokud na smlouvě záleží.
  • Použijte stav načítání, pokud undefined znamená „ještě nenačteno“.
  • Použijte volitelné řetězení, když je absence oprávněná, nikoli jako náhradu za pochopení špatných dat.
  • Po refaktoringu zkontrolujte přejmenované nebo vynechané propy.
  • Dodejte vykresleným položkám seznamu stabilní klíče z dat, jak doporučuje dokumentace Reactu pro vykreslování seznamů.

Pro hypotetický seznam produktů byla příčinou chyby skutečnost, že první vykreslení obdrželo undefined tam, kde komponenta okamžitě očekávala pole. V reálné aplikaci může stejná chybová zpráva pocházet z inicializace stavu, propů, vnořených vlastností nebo dat z API. Nejprve opravte datovou smlouvu, poté vyberte ochranu při vykreslování, která přesně reprezentuje, co „chybějící“ znamená ve vašem UI.

Zanechat komentář

Jak opravit chybu „PyTorch CUDA Out of Memory“ během trénování modelu

Jak opravit chybu „PyTorch CUDA Out of Memory“ během trénování modelu

Opravte chyby nedostatečné paměti CUDA v PyTorch pomocí praktického postupu: měřte paměť GPU, zmenšete pracovní množinu, použijte AMP a akumulaci gradientů, ukládejte aktivace (checkpointing) a laděte alokátor pouze v případě potřeby.

Jak opravit chybějící hlavičku CORS Access-Control-Allow-Origin v Express.js

Jak opravit chybějící hlavičku CORS Access-Control-Allow-Origin v Express.js

Opravte chybu CORS s chybějící hlavičkou Access-Control-Allow-Origin v Express.js diagnostikou původu, bezpečnou konfigurací cors, zpracováním preflight požadavků a ověřením hlaviček.

Jak opravit chybu „Cannot read properties of undefined (reading 'map')“ v Reactu

Jak opravit chybu „Cannot read properties of undefined (reading 'map')“ v Reactu

Opravte chybu Reactu „Cannot read properties of undefined (reading 'map')“ vysledováním nedefinované hodnoty, opravou stavu a dat z API a přidáním bezpečných ochranných mechanismů při vykreslování.

Jak opravit chybu Module Not Found: Nelze vyřešit fs ve Webpacku

Jak opravit chybu Module Not Found: Nelze vyřešit fs ve Webpacku

Opravte chybu Webpacku „Nelze vyřešit 'fs'“ správným řešením: přesuňte kód pouze pro Node na server, použijte závislost bezpečnou pro prohlížeč, nastavte fs:false pouze u volitelných funkcí nebo správně cílte na Node.

Jak opravit chybu „Supabase API Key Not Found“ v proměnných prostředí

Jak opravit chybu „Supabase API Key Not Found“ v proměnných prostředí

Opravte chybějící klíče API Supabase v Next.js, Vite, Node, nasazeních a Edge Functions. Použijte aktuální názvy publikovatelných/secret klíčů, správné soubory env a bezpečné kroky ověření.

Jak opravit chybu „Flutter Command Not Found“ (cesta) v systému macOS

Jak opravit chybu „Flutter Command Not Found“ (cesta) v systému macOS

Opravte chybu „flutter: command not found“ v systému macOS nalezením SDK Flutter, přidáním složky bin do proměnné PATH, znovu načtením Zsh a ověřením nastavení.

Jak opravit chybu „Port 8080 je již používán“ v terminálu na Windows, macOS a Linuxu

Jak opravit chybu „Port 8080 je již používán“ v terminálu na Windows, macOS a Linuxu

Opravte chybu „Port 8080 je již používán“ nalezením procesu, který port vlastní, jeho bezpečným zastavením, řešením problémů s Dockerem nebo výběrem nového portu.

Jak opravit chybu Django „ImproperlyConfigured: The SECRET_KEY Setting Must Not Be Empty“

Jak opravit chybu Django „ImproperlyConfigured: The SECRET_KEY Setting Must Not Be Empty“

Opravte chybu Django SECRET_KEY must not be empty kontrolou aktivního modulu nastavení, proměnných prostředí, generování klíče a konfigurace produkčního prostředí.

Jak opravit chybu „Connection Refused“ u PostgreSQL na localhostu portu 5432

Jak opravit chybu „Connection Refused“ u PostgreSQL na localhostu portu 5432

Opravte chybu „connection refused“ u PostgreSQL na localhost:5432 kontrolou stavu serveru, nástroje pg_isready, naslouchání na portu, souboru postgresql.conf, mapování Dockeru a ověřování.

Jak opravit chybu „Hydration failed because the initial UI does not match“

Jak opravit chybu „Hydration failed because the initial UI does not match“

Opravte nesoulad hydratace v Reactu nebo Next.js tak, aby se serverové HTML shodovalo s prvním vykreslením na klientovi, a poté ověřte výsledek ve vývojovém i produkčním prostředí.