Over the next few weeks we’ll be building a digital Pokemon (simplified) card game. Complete with features like:
- Viewing and searching Pokemon “cards”
- Viewing and comparing stats
- Adding Pokemon cards to a deck
- Opportunities for you to expand functionality like dueling 2 Pokemon against each other.
- Fork this repo, clone to your desktop, and install dependencies:
npm install
- Start the server, and navigate to
localhost:1234npm run start
- Lint
.jsand.jsxfilesnpm run lint
GOAL: Using the React Bootstrap CSS Framework and the pokeapi:
- Fetch and render a list of 150 Pokemon cards - each with limited information (picture, name, abilities).
- Add a search feature to find a specific Pokemon.
Use the following instructions to guide your coding:
- Get the Pokemon!
- Fetch using the provided
pokeApiurl and set the returned data on state. - NOTE: The API returns a
data.resultsarray of objects, each one containing just an ID, a Name, and a URL. That returned URL will be used to fetch the rest of the data about the Pokemon. Here is an exampleresponsefrom the API.
- Fetch using the provided
- Iterate over the
pokemonListarray and for each pokemon render a single PokemonCard passing the name and url to the card. - Inside
PokemonCardfetch the provided URL and set the returned data from this URL on state- Note the return of this URL is vastly different from the return of the above
pokeApiURL. This URL will return all the data about a specific Pokemon. - For now, we’ll specifically want to pay attention to
spritesandabilities. - Here is an example of the response from this URL
- Note the return of this URL is vastly different from the return of the above
- Import a
Cardcomponent from react-bootstrap, and render it, including the following pieces:Card.Img- usepokemon.sprites.front_defaultas the img’s srcCard.Titlewith thenameof the pokemonCard.Textwith aulof all of that pokemon’s abilities- At this point, we should see a list of all the pokemon cards in the UI, though it may be ugly and/or unstyled
- In
App.jsadd anInputGroupwith aFormControlto allow user to enter pokemon name (see react-bootstrap InputGroup docs) - Connect an
onChangethat will filter the list of pokemon- There’s a few ways to handle this, refer to previous exercises for inspiration or come up with another way on your own!
- At this point the list should be searchable
- Style the page a little bit more, try to center things and render the whole page in a
Containerand manyRow/Col - Save and push your changes back to your GitHub repository!
GOAL: By the end of this section, clicking on a single Pokemon should navigate to that pokemon’s Details page and display all of their stats!
- Continue from your Pokeverse repo that you used in the last section and checkout a new branch:
- To checkout a new branch, run the following command:
git checkout -b adds-react-router
- This will create a new branch named
”adds-react-router”and then switch your local branch version to the new branch. When you’re done with this lesson feel free to merge your new branch intomainor better yet - submit a Pull Request to your repo and review your code yourself and then merge it in! 🚀
- Install React Router:
npm i react-router-dom@6- Create a new directory
src/routes/and in it create a file calledHome.js
mkdir src/routes/
touch src/routes/Home.js - Move almost everything out of App.js into routes/Home.js EXCEPT:
- The initial
useEffectthat fetches all of the pokemon - The
pokemonListstate - The container
divand<Navigation />
- The initial
Homeshould expect thepokemonListarray as a prop - and will handle the searching and filtering of thefilteredPokemonarray.- Create a new file
src/routes/PokemonDetails.js. This component will display all of the pokemon's stats! We'll come back to this component later. - In
Appset up aBrowserRouterthat wraps everything that's left in the component. - Inside of the
<BrowserRouter>, below<Navigation />, add a<Routes>component. - Inside of
Routes, add 2 routes:- One with a path of
"/"that renders the newly cratedHomecomponent and passespokemonListto it - The other with a path of
"/:name"that renders the newly created PokemonDetails component. Notice the:before name, this is a special syntax for URL params, we'll be able to access the value of name later!
- One with a path of
- Inside of the
PokemonDetailscomponent:- Add a new state of pokemon with initial value of
null - Import and call
useParams. This is how we'll access thatnameparam we added earlier!
const params = useParams();
- Inside of a
useEffect,fetchall of the details about this pokemon using the name from the params and thensetPokemonwith the fetched data.
https://pokeapi.co/api/v2/pokemon/${params.name}- Since we'll be waiting for data to be fetched, we can conditionally render the page! To do this we can add 2 separate
return statements. The first will be wrapped in an if statement
if (!pokemon) { return <>loading...</>; } return ( // ... the rest of the component here )
- Add a new state of pokemon with initial value of
- Now let's add all of the stats about the pokemon like such:
height: {pokemon.height}
weight: {pokemon.weight}
abilities: iterate over pokemon.abilities, and for each ability render the ability.ability.name
types: iterate over pokemon.types and for each type render the type.type.name
stats: iterate over pokemon.stats and for each stat render the stat.stat.name and stat.base_stat
- Finally, let's link to the newly created route and component! In
PokemonCard.js, wrap the{name}of the Pokemon with a<Link>with a to value of/${name}
<Link to={`/${name}`}>
{name}
</Link>- BONUS #1: Right now
PokemonDetailsis probably just plain text, and pretty boring looking. Since we already have React Bootstrap installed, check out theComponentssection of the React Bootstrap docs and see how you can style the page! - BONUS #2: Right now the All Pokemon link works like a normal anchor tag (when clicked the page loads/refreshes), but we want to use React Router, with no page refresh! Convert the
Nav.Linkto use the properties of theLinkcomponent by passing it theas={Link}prop, and switch out thehreffor a to prop. The react-bootstrap docs have examples of other components likeNav.Itemusing theasprop.
We will be updating our existing Pokeverse application with the following:
- Each pokemon card should have an “Add to Favorites” button.
- The pokemon that have been added to favorites can be viewed navigating to the new route,
/favorites. - The favorites will be stored in context, in addition to
setFavoriteandremoveFavoritefunctions to update the favorites list.
- Continue from your Pokeverse repo you already have and checkout a new branch:
git checkout -b adds-context- When you’ve finished, merge your new branch into
mainor better yet - submit a Pull Request!
- In
FavoritesProvider.jspass a value to theProvidergiving access tofavorites,addFavorite, andremoveFavorite - In
App.jswrap the returned component in theFavoritesProviderimported fromFavoritesProvider.js - Create a new file in routes called
Favorites.js. For now you can just export an empty React component. We’ll come back to this file later. - Add a route to
/favorites- Back in
Appadd a new route with the path’/favorites’and the element of<Favorites />(of course, after importing Favorites). That’s it forApp.js! - In
Navigationadd anotherNavLinkto’/favorites’with the text of something like “My Favorites” or “My Deck”
- Back in
- Connect the addFavorite to PokemonCard!
- First, import
FavoritesContextfrom ’FavoritesProvider’ as well asuseContextfrom ’react’. - Destructure
addFavoriteout of context
const { addFavorite } = useContext(FavoritesContext);
- Import Button from Bootstrap
- Beneath the
<Card.Text>section, add a<Button>with anonClickthat when clicked callsaddFavoriteand pass the name to it.
<Button variant="primary" onClick={() => addFavorite(name)}> Add to Favorites </Button>
- First, import
- Back in
Favorites, follow the same pattern from PokemonCard to pull out favorites from context.- Destructure favorites
- Map over favorites and for each favorite render a
<PokemonCard>passing the prop ofname={favorite} - TIP: To get the styling similar to what we have on the main page, take a look at how you’re rendering all of the cards in
Home.js. It should be structured something like this:Container>Row>1 Colfor each PokemonCard
- Try navigating to
/favoritesnow - you should see any pokemon that you clicked “Add to Favorites” here! You also may notice that you can click “Add to Favorites” over and over and get the same pokemon duplicated over and over. Take a look at the first item of the Bonus to fix that! - BONUS: After someone clicks “Add to Favorites”, they shouldn’t be able to click that button again. We already have a
removeFavoritefunction available in Context that can be helpful here!- If a pokemon is already in
favorites, instead of rendering an Add to Favorites button on the PokemonCard let’s render a Remove from Favorites button! - Try using a ternary for this
{someExpression ? ( <RenderThisThingIfSomeExpressionIsTruthy /> ) : ( <RenderThisThingIfSomeExpressionIsFalsey /> )} // or, in plain english: {ifThis ? ( then this ) : ( else this )}
- Try utilizing includes for this. If favorites includes name, then render an “Add to Favorites” button, else render a “Remove from Favorites” button.
- If a pokemon is already in
Made with
♥️ at Multiverse



