Hello, I wrote this guide with the purpose to show how to develop a simple app using react, and configuring webpack and babel by hand. I hope that could be helpful if you are starting to work with this technologies, or if you have plans to use them in the near future.
Before start
Before start coding we need to add some software to our computer:
- We'll use npm to manage the app dependencies, so we need to install nodejs.
- A code editor, you can choose your favorite, but I recommend to use VS Code.
And that's it, now we will are able to develop the app.
Let's Start
The first thing that we need to do is initialize the app, to do this we need to use a terminal and move to the folder where we'll create the app (you can do this with the command cd [directory]
), once we are on that directory we need to type the following command in the console:
npm init
This command will open a prompt to ask you some initial configurations for the app in order to generate the package.json file:
After fill the information and type yes to save, we should be able to open VS code or the code editor that we choose, once we open the folder we need to open the embedded terminal on the editor and continue installing the dependencies from there.
Install the dependencies
First we need to install the app dependencies, in this case we gonna use react, react-dom, and axios, so we'll to type in the terminal the following command:
npm i react react-dom axios
Then we should proceed to install the development dependencies, this dependencies are only to be able to have a development environment to test the app, add libraries, check errors, and run the app in the local host environment.
For this app, we will use webpack and babel to generate the bundles, so we'll run this command on the console to install them as dev dependencies:
npm i @babel/core@^7.12.3 babel-loader@^8.1.0 babel-preset-react-app@^7.0.2 css-loader@^5.0.0 html-webpack-plugin@^4.5.0 style-loader@^2.0.0 webpack@^4.44.2 webpack-cli@^3.3.12 webpack-dev-server@^3.11.0 --save-dev
* In this case I specify the library version to avoid problems when we will start configuring webpack and babel
Once we install all the dependencies the package.json file should look in the following way:
{
"name": "pokeapp",
"version": "1.0.0",
"description": "demo app",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server"
},
"author": "PHD",
"license": "ISC",
"dependencies": {
"axios": "^0.20.0",
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
"devDependencies": {
"@babel/core": "^7.12.3",
"babel-loader": "^8.1.0",
"babel-preset-react-app": "^7.0.2",
"css-loader": "^5.0.0",
"html-webpack-plugin": "^4.5.0",
"style-loader": "^2.0.0",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
},
"babel": {
"presets": [
"babel-preset-react-app"
]
}
}
* We added some babel configuration to transpile the react app correctly.
"babel": {
"presets": [
"babel-preset-react-app"
]
}
* Also we add in the scripts section the command a script start the app when we'll finish the first configurations.
"scripts": {
"start": "webpack-dev-server"
},
Configure webpack
Now we have our dependencies ready, the following step is to setup webpack, to do this we need to add a webpack.config.js file in the root folder, this step is necessary only to have a better control of what happens when we build the app.
Webpack expects a list of options to generate the bundles based on that configuration, so we need to export that options in the following way:
const webpack = require("webpack");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
process.env.NODE_ENV = "development";
module.exports = {
... // webpack options goes here
};
To correctly setup webpack we need to set the following options on the exports section:
-
mode. This setting is to allow to webpack's built-in optimizations that correspond to each environment (development or production).
mode: "development"
-
target. In this option we could select if the deployment should be on the server or on the browser, we can do more configurations like have multiple targets but are off the scope of this guide.
target: "web"
-
devtool. With this option we can control if we generate a source map and which type of source map we would use, the source map allow us to debug easily our compiled code on the browser.
devtool: "cheap-module-source-map"
-
entry. This setting allow us to define the entry point of the app.
entry: "./src/index"
-
output. This key indicate to webpack how and where it should output the bundles and assets.
output: { path: path.resolve(__dirname, "build"), publicPath: "/", filename: "pokebundle.js", }
-
devServer. In this guide we would use devServer to develop the app, this option allow us to configure how this server should run in the local host.
devServer: { open: true, stats: "minimal", overlay: true, historyApiFallback: true, disableHostCheck: true, headers: { "Access-Control-Allow-Origin": "*" }, https: false, }
-
plugins. This key is to configure the webpack plugins, those plugins help us to do extra actions when we bundle the app, in this case we gonna use HtmlWebpackPlugin to serve some html files with the app bundle.
plugins: [ new HtmlWebpackPlugin({ template: "src/index.html", }), ]
-
module. This option determine how webpack would process the different modules of the app.
module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: ["babel-loader"], }, { test: /(\.css)$/, use: ["style-loader", "css-loader"], }, ], }
The complete webpack.config.js file should looks like the following one:
const webpack = require("webpack");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
process.env.NODE_ENV = "development";
module.exports = {
mode: "development",
target: "web",
devtool: "cheap-module-source-map",
entry: "./src/index",
output: {
path: path.resolve(__dirname, "build"),
publicPath: "/",
filename: "pokebundle.js",
},
devServer: {
open: true,
stats: "minimal",
overlay: true,
historyApiFallback: true,
disableHostCheck: true,
headers: { "Access-Control-Allow-Origin": "*" },
https: false,
},
plugins: [
new HtmlWebpackPlugin({
template: "src/index.html",
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
{
test: /(\.css)$/,
use: ["style-loader", "css-loader"],
},
],
},
};
Run the app
We gonna use a simple folder structure just a src
main folder and inside other two folders api
and components
where we will put all our files:
Now is time to start coding
The first file that we need to add is the app main component, to do that go to the components
folder and create an App.js file, then put inside that file the following code:
import React from "react";
function App() {
return (
<div className="container">
Pokedex goes here
</div>
);
}
export default App;
This react hook returns a simple component that renders a div with some text inside.
To render this component properly we need to add the entry point to the app, to do that go to src
folder and create a index.js file, then type the following code:
import React from "react";
import { render } from "react-dom";
import App from "./components/App";
document.addEventListener("DOMContentLoaded", () => {
render(<App />, document.getElementById("app"));
});
This code is to render the app in an html page, the render function looks for an element with id "app" after the DOM content is loaded, and then try to render our component there.
But we don't have any html page yet, so we need to add an html page in the src
folder to use it as a template for the app, please create an index.html file and put the following content there:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Pokedex</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
crossorigin="anonymous"
/>
<script
src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
crossorigin="anonymous"
></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Notice how we added some style sheets to the html head, we did that to use Bootstrap in the app.
Now we are ready to run the app, just go to the console and type npm start
this command should bundle the app and open the default browser with the running application.
Get Pokemon information
To get the Pokemon information we gonna use the Pokemon API this APIs provide some endpoints that we could use to get all the information that we need for the app, but first we need to create some files to connect the app to any REST API.
Add the following files to the api
folder ApiService.js and ApiUtils.js, then put the following code in the ApiService.js file:
import axios from "axios"; // this library is to fetch data from REST APIs
import { handleError, handleResponse } from "./ApiUtils";
const httpRequest = (method, url, request, headers) => {
// return a promise
return axios({
method,
url,
data: request,
headers,
})
.then((res) => {
const result = handleResponse(res);
return Promise.resolve(result);
})
.catch((err) => {
return Promise.reject(handleError(err));
});
};
const get = (url, request, headers) => {
let queryString = "";
if (request && Object.keys(request).length > 0) {
queryString += "?";
let len = Object.keys(request).length,
cnt = 0;
// transform the request object in a query string
for (let key in request) {
cnt++;
queryString += `${key}=${request[key].toString()}`;
if (len > cnt) queryString += "&";
}
}
return httpRequest("get", `${url}${queryString}`, request, headers);
};
const deleteRequest = (url, request, headers) => {
return httpRequest("delete", url, request, headers);
};
const post = (url, request, headers) => {
return httpRequest("post", url, request, headers);
};
const put = (url, request, headers) => {
return httpRequest("put", url, request, headers);
};
const patch = (url, request, headers) => {
return httpRequest("patch", url, request, headers);
};
const Api = {
get,
delete: deleteRequest,
post,
put,
patch,
};
export default Api;
In this file we use axios
to do the REST requests, we handle the responses with other two functions handleResponse
and handleError
those methods are imported from the ApiUtils.js file, also we add some logic to the get
method to have a consistent way to do any REST request, at the end of the file we export all the methods inside an Api object.
For the ApiUtils.js file we need to write the following code, to handle appropriately the server responses:
export function handleResponse(response) {
if (
response.status === 200 ||
response.status === 202 ||
response.statusText === "OK" ||
response.statusText === "Created"
)
return response.data;
if (response.status === 400) {
// So, a server-side validation error occurred.
// Server side validation returns a string error message, so parse as text instead of json.
const error = response.statusText();
throw new Error(error);
}
throw new Error("Network response was not ok.");
}
// In a real app, would likely call an error logging service.
export function handleError(error) {
console.error("API call failed. " + error);
throw error;
}
Now is time to connect the app to the Pokemon API, we need to create a PokemonService.js file inside of api
folder, in this file we would add all the methods to get the Pokemon information.
First we need to import the api dependencies into the service:
import ApiService from "./ApiService";
Then we could define the three async methods that we'll use:
-
getKantoPokemon. This method will get a list with all kanto Pokemon, with this list we'll be able to get more data for all the pokemons.
export const getKantoPokemon = async () => { try { let response = await ApiService.get(`https://pokeapi.co/api/v2/pokemon`, { limit: 151, }); return response.results; } catch (err) { throw err; } };
-
getPokemonData. This method is to get the Pokemon details, this method require an URL to get the Pokemon information.
export const getPokemonData = async (url) => { try { let response = await ApiService.get(url); return response; } catch (err) { throw err; } };
-
getPokemonKantoData. This method use the first two methods, the first one to get all kanto Pokemon and the second one to get the details of all the pokemons on the response of the first call.
export const getPokemonKantoData = async () => { try { //get pokemon list let pokemons = await getKantoPokemon(); //get promises to obtain data for all pokemon in the list let pokemonPromises = pokemons.map((p) => getPokemonData(p.url)); //return all the pokemon data return await Promise.all(pokemonPromises); } catch (err) { throw err; } };
The complete code of this file is the following:
import ApiService from "./ApiService";
export const getKantoPokemon = async () => {
try {
let response = await ApiService.get(`https://pokeapi.co/api/v2/pokemon`, {
limit: 151,
});
return response.results;
} catch (err) {
throw err;
}
};
export const getPokemonData = async (url) => {
try {
let response = await ApiService.get(url);
return response;
} catch (err) {
throw err;
}
};
export const getPokemonKantoData = async () => {
try {
//get pokemon list
let pokemons = await getKantoPokemon();
//get promises to obtain data for all pokemon in the list
let pokemonPromises = pokemons.map((p) => getPokemonData(p.url));
//return all the pokemon data
return await Promise.all(pokemonPromises);
} catch (err) {
throw err;
}
};
Create the Pokedex components
We'll use three components, we need to create the home
folder inside of components
and then proceed to create the following files:
HomeContainer.js this component will act as our container.
PokemonList.js this component will display all the list of Pokemons.
PokemonDetail.js in this component we will display the Pokemon details once the user click on one element of the list.
Also we need to add some css styles, so to handle those styles in one file we need to create the pokemon.css
file in the src
folder.
PokemonList component
In this functional component we need to receive the Pokemon list, and which is the selected Pokemon as props, the first prop is to display all Pokemons in a friendly way, and the second one is to be able to highlight the selected Pokemon.
First we need to do the imports that we'll use:
import React from "react";
import "../../pokemon.css";
Then we need to create the functional component:
function PokemonList({ pokemons, selectPokemon }) {
... // draw Pokemon function goes here
... // return goes here
};
If the pokemons
array prop have records we'll return an <li>
item for each object in the array, in this tag we can properly render the items to display them in a friendly way:
const drawPokemon = () => {
return pokemons.map((p, id) => (
<li
key={id}
onClick={() => selectPokemon(p.id)}
className={
p.selected
? "list-group-item d-flex pokemon-item-list selected"
: "list-group-item d-flex pokemon-item-list"
}
>
<img className="col-3" src={p.sprites.front_default} />
<p className="col-4 pokemon-text-list">N.º {p.id}</p>
<p className="col-5 pokemon-text-list">{p.name}</p>
</li>
));
};
In the return of the component, we need to check if the pokemons
prop length is greater than 0, because we'll get the data from the server, and when the component is rendered at the screen this prop will not have data:
return <ul className="list-group">{pokemons.length > 0 && drawPokemon()}</ul>;
And finally don't forget to export the component to be able to use it:
export default PokemonList;
The complete file component should look like the following:
import React from "react";
import "../../pokemon.css";
function PokemonList({ pokemons, selectPokemon }) {
const drawPokemon = () => {
return pokemons.map((p, id) => (
<li
key={id}
onClick={() => selectPokemon(p.id)}
className={
p.selected
? "list-group-item d-flex pokemon-item-list selected" // the selected class is to highlight the Pokemon selected
: "list-group-item d-flex pokemon-item-list"
}
>
<img className="col-3" src={p.sprites.front_default} />
<p className="col-4 pokemon-text-list">N.º {p.id}</p>
<p className="col-5 pokemon-text-list">{p.name}</p>
</li>
));
};
return <ul className="list-group">{pokemons.length > 0 && drawPokemon()}</ul>;
}
export default PokemonList;
PokemonDetail component
This functional component will render the details of the selected Pokemon, the name, a picture, the Pokemon types, etc.
First we need to import the libraries that we'll use:
import React from "react";
Then we need to create the component body:
function PokemonDetail({ pokemon }) {
... // getTypeStyleFunction goes here
... // return goes here
}
In this component we use the getTypeStyle function, this function is to used to get some css styles that rely on the Pokemon type:
const getTypeStyle = (type) => {
let backgroundColor = "";
switch (type) {
case "grass":
backgroundColor = "#9bcc50";
break;
case "poison":
backgroundColor = "#b97fc9";
break;
case "fire":
backgroundColor = "#fd7d24";
break;
case "flying":
backgroundColor = "#3dc7ef";
break;
case "water":
backgroundColor = "#4592c4";
break;
case "bug":
backgroundColor = "#729f3f";
break;
case "normal":
backgroundColor = "#a4acaf";
break;
case "electric":
backgroundColor = "#eed535";
break;
case "ground":
backgroundColor = "#ab9842";
break;
case "fairy":
backgroundColor = "#fdb9e9";
break;
case "fighting":
backgroundColor = "#d56723";
break;
case "psychic":
backgroundColor = "#f366b9";
break;
case "rock":
backgroundColor = "#a38c21";
break;
case "steel":
backgroundColor = "#9eb7b8";
break;
case "ghost":
backgroundColor = "#7b62a3";
break;
case "ice":
backgroundColor = "#51c4e7";
case "dragon":
backgroundColor = "#f16e57";
default:
backgroundColor = "#000";
break;
}
return { backgroundColor, color: "#FFF", margin: "5px" };
};
Then in the return we render some html to display the Pokemon selected in a friendly way:
return (
<div className="pokemon-image-container">
<h1 className="text-center">
N.º {pokemon.id} {pokemon.name}
</h1>
<img
src={`https://pokeres.bastionbot.org/images/pokemon/${pokemon.id}.png`}
className="img-fluid pokemon-image-detail d-block mx-auto"
/>
<div className="pokemon-box-details">
<ul className="list-group list-group-horizontal justify-content-center">
{pokemon.types.length > 0 &&
pokemon.types.map((t, idx) => (
<li
key={idx}
className="list-group-item d-flex pokemon-list-details"
style={getTypeStyle(t.type.name)}
>
{t.type.name}
</li>
))}
</ul>
</div>
</div>
);
Finally don't forget to export the component:
export default PokemonDetail;
The complete file component should look like the following:
import React from "react";
function PokemonDetail({ pokemon }) {
const getTypeStyle = (type) => {
let backgroundColor = "";
switch (type) {
case "grass":
backgroundColor = "#9bcc50";
break;
case "poison":
backgroundColor = "#b97fc9";
break;
case "fire":
backgroundColor = "#fd7d24";
break;
case "flying":
backgroundColor = "#3dc7ef";
break;
case "water":
backgroundColor = "#4592c4";
break;
case "bug":
backgroundColor = "#729f3f";
break;
case "normal":
backgroundColor = "#a4acaf";
break;
case "electric":
backgroundColor = "#eed535";
break;
case "ground":
backgroundColor = "#ab9842";
break;
case "fairy":
backgroundColor = "#fdb9e9";
break;
case "fighting":
backgroundColor = "#d56723";
break;
case "psychic":
backgroundColor = "#f366b9";
break;
case "rock":
backgroundColor = "#a38c21";
break;
case "steel":
backgroundColor = "#9eb7b8";
break;
case "ghost":
backgroundColor = "#7b62a3";
break;
case "ice":
backgroundColor = "#51c4e7";
case "dragon":
backgroundColor = "#f16e57";
default:
backgroundColor = "#000";
break;
}
return { backgroundColor, color: "#FFF", margin: "5px" };
};
return (
<div className="pokemon-image-container">
<h1 className="text-center">
N.º {pokemon.id} {pokemon.name}
</h1>
<img
src={`https://pokeres.bastionbot.org/images/pokemon/${pokemon.id}.png`}
className="img-fluid pokemon-image-detail d-block mx-auto"
/>
<div className="pokemon-box-details">
<ul className="list-group list-group-horizontal justify-content-center">
{pokemon.types.length > 0 &&
pokemon.types.map((t, idx) => (
<li
key={idx}
className="list-group-item d-flex pokemon-list-details"
style={getTypeStyle(t.type.name)}
>
{t.type.name}
</li>
))}
</ul>
</div>
</div>
);
}
export default PokemonDetail;
HomeContainer component
This functional component act as a container, so in this component we we'll import the other two components, we gonna get access to the APIs, and also we'll use some hooks like useEffect to get the Pokemon list when the screen loads, useState to handle the state of the component, and send that state as props to the child components.
First we need to import the libraries and components that we'll use:
import React, { useEffect, useState } from "react";
import PokemonList from "./PokemonList";
import PokemonDetail from "./PokemonDetail";
import { getPokemonKantoData } from "../../api/PokemonService";
Then we need to create the component body:
function HomeContainer() {
...// state declarations goes here
...// use effect goes here
...// functions goes here
...// return goes here
}
The states that we need to use will be the following
- pokeList. To handle the complete list of pokemons.
- filteredPokeList. To handle the list of pokemons filtered.
- filter. To set which pokemons we will filter.
- pokemonSelected. To handle the Pokemon selected.
const [pokeList, setPokeList] = useState([]);
const [filteredPokeList, setFilteredPokeList] = useState([]);
const [filter, setFilter] = useState("");
const [pokemonSelected, setPokemonSelected] = useState(null);
Then we need to get the Pokemon list when the app loads, to do this action we need to use the useEffect hook, to call the API that gets the information:
useEffect(async () => {
try {
let pokemons = await getPokemonKantoData();
setFilteredPokeList(pokemons);
setPokeList(pokemons);
} catch (err) {
alert("an error occurs");
console.error(err);
}
}, []);
To have the filter functionality we can use a function to set the state filteredPokeList
based on the received value:
const filterPokemon = (value) => {
setFilter(value); // set the filter value
setFilteredPokeList(
pokeList.filter((p) => p.name.toLowerCase().includes(value.toLowerCase()))
); // set the pokemons that match with the value
};
To highlight the selected Pokemon, and also to display the Pokemon details, we need to create a function that sets the pokemonSelected
state:
const handleSelect = (pokemonId) => {
setPokemonSelected(pokeList.filter((p) => p.id === pokemonId)[0]); // set the selected Pokemon to display the details
setFilteredPokeList(
filteredPokeList.map((p) =>
p.id === pokemonId
? { ...p, selected: true }
: { ...p, selected: false }
)
); // filter the list of pokemons to display
};
Finally, we need to return the container structure to display the app:
return (
<div className="row pokemon-app-container">
<div className="col-6">
{pokemonSelected && <PokemonDetail pokemon={pokemonSelected} />}
</div>
<div className="col-6 pokemon-list-container">
<div style={{ height: "10%" }}>
<div className="form-group">
<label>Search</label>
<input
type="text"
className="form-control"
placeholder="Type to search a pokemon..."
value={filter}
onChange={(event) => {
let { value } = event.target;
filterPokemon(value);
}}
/>
</div>
</div>
<div style={{ height: "90%", overflowY: "auto" }}>
<PokemonList
pokemons={filteredPokeList}
selectPokemon={handleSelect}
/>
</div>
</div>
</div>
);
Finally export the component to be able to use it:
export default HomeContainer;
The complete code of this component should look like the following:
import React, { useEffect, useState } from "react";
import PokemonList from "./PokemonList";
import PokemonDetail from "./PokemonDetail";
import { getPokemonKantoData } from "../../api/PokemonService";
function HomeContainer() {
useEffect(async () => {
try {
let pokemons = await getPokemonKantoData();
console.log(pokemons);
setFilteredPokeList(pokemons);
setPokeList(pokemons);
} catch (err) {
alert("an error occurs");
console.error(err);
}
}, []);
const [pokeList, setPokeList] = useState([]);
const [filteredPokeList, setFilteredPokeList] = useState([]);
const [pokemonSelected, setPokemonSelected] = useState(null);
const [filter, setFilter] = useState("");
const handleSelect = (pokemonId) => {
setPokemonSelected(pokeList.filter((p) => p.id === pokemonId)[0]);
setFilteredPokeList(
filteredPokeList.map((p) =>
p.id === pokemonId
? { ...p, selected: true }
: { ...p, selected: false }
)
);
};
const filterPokemon = (value) => {
setFilter(value);
setFilteredPokeList(
pokeList.filter((p) => p.name.toLowerCase().includes(value.toLowerCase()))
);
};
return (
<div className="row pokemon-app-container">
<div className="col-6">
{pokemonSelected && <PokemonDetail pokemon={pokemonSelected} />}
</div>
<div className="col-6 pokemon-list-container">
<div style={{ height: "10%" }}>
<div className="form-group">
<label>Search</label>
<input
type="text"
className="form-control"
placeholder="Type to search a pokemon..."
value={filter}
onChange={(event) => {
let { value } = event.target;
filterPokemon(value);
}}
/>
</div>
</div>
<div style={{ height: "90%", overflowY: "auto" }}>
<PokemonList
pokemons={filteredPokeList}
selectPokemon={handleSelect}
/>
</div>
</div>
</div>
);
}
export default HomeContainer;
The Pokemon css stylesheet
I don't want to go deep in the css because I think is out of the scope of this guide, so I only add the style sheet here:
.pokemon-item-list {
border-radius: 40px !important;
margin-top: 10px;
margin-bottom: 10px;
border-width: 0px;
}
.pokemon-item-list.selected {
background-color: #e3350d;
color: white;
border-width: 1px;
}
.pokemon-item-list:hover {
border-width: 1px;
background-color: #E2E2E2;
color: white;
}
.pokemon-text-list {
font-size: 24px;
margin-top: 20px;
}
.pokemon-app-container {
height: 100vh;
}
.pokemon-list-container {
height: 100%;
overflow-y: auto;
}
.pokemon-image-container {
margin-top: 4rem;
border: 1px solid #F2F2F2;
background-color: #F2F2F2;
border-radius: 20px;
padding: 10px;
}
.pokemon-image-detail {
height: 400px;
}
.pokemon-list-details {
margin-top: 20px;
border-width: 0px;
}
.pokemon-box-details {
margin-top: 10px;
}
Ending the app
Finally we need to update our App.js
file this to load the components that we created:
import React from "react";
import Home from "./Home/HomeContainer"; // import the container component
// return the Home component
function App() {
return (
<div className="container">
<Home />
</div>
);
}
export default App;
With this the app should be completed, but we can improve many parts of them, like add proptypes, use redux, refactor the code in some parts, optimize the bundles, etc.
You can get the complete code in the following repository PokeApp
If you are here, I want to say you thank you so much for read this guide, and if you have any comment I really appreciate your feedback.
Top comments (5)
Use object literals instead of switch case and you have sort code.
This is example in my pokedex app.
Btw, you can easily make it more type-safe:
You can do even better, just use enums:
Then, just access it:
Thanks for your comment, I agree with you, the object literals looks better on js code, but my intention with this tutorial is to guide developers that have less experience in javascript, so a switch case sentence might looks more natural for them, I think that I can do a second part of this tutorial and do some code refactoring in some places, and also apply redux and other technologies, thanks for the feedbak :)
No problem pro. Pokedex is my favorite app when I start begin new frontend Framework. Thanks for your post :) .