Projekt: Pokémon Memory Game
Březen 2026
Po zvládnutí základů Reactu přišla první opravdová výzva z The Odin Project – paměťová hra. Cílem bylo vytvořit aplikaci, která komunikuje s externím API, dynamicky mění UI a hlídá skóre uživatele.
Co projekt dělá
Hra testuje paměť hráče pomocí náhodně generovaných karet Pokémonů:
- Načtení 12 unikátních Pokémonů z PokeAPI při startu.
- Míchání pořadí karet po každém kliknutí.
- Sledování aktuálního skóre (Current Score).
- Ukládání nejvyššího dosaženého výsledku (Best Score).
- Reset hry, pokud hráč klikne na stejného Pokémona dvakrát.
Práce s API a useEffect
Karty se načítají asynchronně. Použil jsem useEffect, aby se data stáhla hned při prvním renderu komponenty:
useEffect(() => {
const getPokemons = async () => {
const response = await fetch(
"[https://pokeapi.co/api/v2/pokemon?limit=12](https://pokeapi.co/api/v2/pokemon?limit=12)",
);
const data = await response.json();
// transformace dat a nastavení stavu...
};
getPokemons();
}, []);
Nejtěžší bylo zajistit, aby se obrázky načetly dříve, než se karty zobrazí, aby uživatel neviděl prázdná místa.
Logika míchání a stavu
Hlavní logiku hry drží stav cards. Po každém kliknutí se pole s Pokémony zamíchá, což vynutí re-render komponenty a změnu pozic:
const handleCardClick = (id) => {
if (clickedCards.includes(id)) {
resetGame();
} else {
setClickedCards([...clickedCards, id]);
setScore(score + 1);
shuffleArray(cards);
}
};
Komponentová struktura
Aplikaci jsem rozdělil na několik znovupoužitelných částí:
- Header: Zobrazuje název a aktuální/nejlepší skóre.
- CardGrid: Kontejner, který mapuje pole karet.
- Card: Jednotlivá karta s obrázkem a jménem Pokémona.
Co bylo náročné
- Asynchronní fetch: Pochopit, jak správně řetězit požadavky na API, abych dostal nejen jména, ale i URL obrázků.
- Imutabilita stavu: Musel jsem si dávat pozor, abych neměnil původní pole v
useStatepřímo, ale vždy vytvářel kopii. - Styling: Zarovnání karet pomocí CSS Gridu tak, aby hra vypadala dobře i na mobilu.
Co jsem se naučil
React Hooks: Práce s useState pro skóre a useEffect pro side-efekty (volání API).
Práce s daty: Mapování polí objektů a jejich transformace pro potřeby UI.
Lifecycle komponenty: Kdy se co vykresluje a proč je důležité čistit side-efekty.
Conditional Rendering: Zobrazení loading spinneru, zatímco se čeká na data z API.
Co dál
Projekt je funkční, ale v budoucnu bych chtěl přidat:
- Možnost vybrat si generaci Pokémonů.
- Animace pomocí Framer Motion při míchání karet.
- Zvukové efekty při kliknutí a prohře.
- LocalStorage pro trvalé uložení rekordního skóre.
GitHub: Pokemon_memory_game