{"id":4672,"date":"2024-05-11T11:15:57","date_gmt":"2024-05-11T11:15:57","guid":{"rendered":"https:\/\/nikola-breznjak.com\/blog\/?p=4672"},"modified":"2024-05-11T11:38:54","modified_gmt":"2024-05-11T11:38:54","slug":"getting-started-with-react-by-building-a-pokemon-search-application","status":"publish","type":"post","link":"https:\/\/nikola-breznjak.com\/blog\/javascript\/react\/getting-started-with-react-by-building-a-pokemon-search-application\/","title":{"rendered":"Getting started with React by building a Pokemon search application"},"content":{"rendered":"<h2>TL;DR<\/h2>\n<p>In the previous tutorial I showed you how to <a href=\"https:\/\/nikola-breznjak.com\/blog\/javascript\/getting-started-with-vue-js-3-by-building-a-pokemon-search-application\/\">get started with Vue.js 3 by building a Pokemon search application<\/a>. I&#8217;m going to do the same here, but by using <a href=\"https:\/\/react.dev\/\">React<\/a>.<\/p>\n<p>In this post, you&#8217;ll learn how to use <a href=\"https:\/\/create-react-app.dev\/\">create-react-app<\/a> (official React project scaffolding tool) to build a <strong>React<\/strong> application for searching Pokemon by using <a href=\"https:\/\/pokeapi.co\/docs\/v2#pokemon\">Poke API<\/a>.<\/p>\n<h2>Introduction &#8211; The Battle is Over Indeed<\/h2>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/CseGOCb.png\" alt=\"\" \/><\/p>\n<p>A few years ago, this was a popular meme. It was funny because it was true \ud83d\ude42<\/p>\n<p>However, it seems that the craziness has settled down a bit and that the war is seemingly over. For now. These top four (top 5 lists are overrated \ud83d\ude09) frameworks established themselves:<\/p>\n<ul>\n<li><a href=\"https:\/\/angular.io\/\">Angular<\/a> (93k)<\/li>\n<li><a href=\"https:\/\/reactjs.org\/\">React<\/a> (218k)<\/li>\n<li><a href=\"https:\/\/svelte.dev\/\">Svelte<\/a> (75k)<\/li>\n<li><a href=\"https:\/\/vuejs.org\/\">Vue.js<\/a> (45k)<\/li>\n<\/ul>\n<p>I added the number of Github <code>*<\/code>s (at the time of this writing), but I don&#8217;t want you to read into that too much \ud83e\udd17<\/p>\n<h2>Analysis paralysis will, well, paralyze you!<\/h2>\n<p>You could argue that there are other options like Ember, Mithril, or good &#8216;ol jQuery even! However, <a href=\"https:\/\/twitter.com\/JoubranJad\/status\/1136030060975017984\">this tweet<\/a> says it all:<\/p>\n<blockquote>\n<p>Developers are fighting over which frontend framework is better.. it&#8217;s not like users know or care. They mostly care about the User Experience. UX should be our focus on the frontend.<\/p>\n<\/blockquote>\n<p>Personally, I stuck to the Angular bandwagon since version 1.0, but that started losing its <em>ooomph<\/em> after versions 2, 3, 4, &#8230; sorry, lost count.<\/p>\n<p>In the previous post I said that Vue.js (due to its progressive and flexible nature) is a perfect fit for teams that have to rewrite old codebases <strong>one step at a time<\/strong>.<\/p>\n<p>I also said that:<\/p>\n<blockquote>\n<p>React&#8217;s JSX just <em>seems wrong<\/em>, and some people, smarter than me, swear by that being TheRightWay\u2122, and I guess we&#8217;re not here to discuss tastes&#8230;<\/p>\n<\/blockquote>\n<p>Well, after playing with it a bit, I can say it&#8217;s not that bad and that indeed one gets used to it.<\/p>\n<p>Also, I recently checked out <a href=\"https:\/\/svelte.dev\/\">Svelte<\/a> and kinda like it, so will be doing a post like this next; stay tuned.<\/p>\n<p>General &#8216;framework war&#8217; kind of questions I tend to answer in the following way:<\/p>\n<blockquote>\n<p>Please just stop with the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Analysis_paralysis\">analysis paralysis<\/a> already.<\/p>\n<p>Do your research, pick a framework (any framework for that matter) that the community is using, use it, and see how far it gets you.<\/p>\n<p>All these talks about X being slow or Y being better just make no sense until you try it yourself for your use case and preference.<\/p>\n<p>Besides, nowadays speed will not be a deciding factor among the top JS frameworks.<\/p>\n<\/blockquote>\n<p>With all this out of the way, fasten your seatbelts, take a venti (or trenta) sized cup of coffee, and let&#8217;s go do something practical! \ud83d\udcaa<\/p>\n<h2>The Demo App<\/h2>\n<p>As said in the intro, we&#8217;ll build an application for searching (and showing) Pokemon by using <a href=\"https:\/\/pokeapi.co\/docs\/v2#pokemon\">Poke API<\/a>.<\/p>\n<p>You can fork the complete source code on <a href=\"https:\/\/github.com\/Hitman666\/PokemonSearch_React\">Github<\/a>, and you can see the app in action <a href=\"https:\/\/hitman666.github.io\/pokemon-search-react\/\">here<\/a>.<\/p>\n<h2>Prerequisites<\/h2>\n<p>Make sure that you have the following tools installed:<\/p>\n<ul>\n<li>Node.js &#8211; here&#8217;s a free but outdated <a href=\"https:\/\/leanpub.com\/meantodo\">step by step guide\/book<\/a> for both Windows and Mac. Or, really, just go to the <a href=\"https:\/\/nodejs.org\/\">main website<\/a> and download the executable for your machine<\/li>\n<li>Git &#8211; here&#8217;s a fun <a href=\"https:\/\/nikola-breznjak.com\/blog\/miscellaneou\/learn-git-fast-job-depends\/\">getting started<\/a> tutorial in case you&#8217;re new to it<\/li>\n<\/ul>\n<h2>Start a new app with create-react-app<\/h2>\n<p>To start the project, run the following command (in your Terminal): <code>npx create-react-app pokemon_search_react<\/code><\/p>\n<p>This command, as their <a href=\"https:\/\/github.com\/reactjs\/create-react\">docs say<\/a>, will install and execute <code>create-react-app<\/code>, the official React project scaffolding tool. The output of that command will be similar to the one below:<\/p>\n<pre><code class=\"language-bash\">Creating a new React app in \/Users\/nikola\/Development\/Testing\/pokemon_search_react.\n\nInstalling packages. This might take a couple of minutes.\nInstalling react, react-dom, and react-scripts with cra-template...\n\nadded 1490 packages in 2m\n\n258 packages are looking for funding\n  run `npm fund` for details\n\nInitialized a git repository.\n\nInstalling template dependencies using npm...\n\nadded 67 packages, and changed 1 package in 8s\n\n262 packages are looking for funding\n  run `npm fund` for details\nRemoving template package using npm...\n\nremoved 1 package, and audited 1557 packages in 1s\n\n262 packages are looking for funding\n  run `npm fund` for details\n\n8 vulnerabilities (2 moderate, 6 high)\n\nTo address all issues (including breaking changes), run:\n  npm audit fix --force\n\nRun `npm audit` for details.\n\nCreated git commit.\n\nSuccess! Created pokemon_search_react at \/Users\/nikola\/Development\/Testing\/pokemon_search_react\nInside that directory, you can run several commands:\n\n  npm start\n    Starts the development server.\n\n  npm run build\n    Bundles the app into static files for production.\n\n  npm test\n    Starts the test runner.\n\n  npm run eject\n    Removes this tool and copies build dependencies, configuration files\n    and scripts into the app directory. If you do this, you can\u2019t go back!\n\nWe suggest that you begin by typing:\n\n  cd pokemon_search_react\n  npm start\n\nHappy hacking!<\/code><\/pre>\n<h2>Running our scaffolded project<\/h2>\n<p>Let&#8217;s run the commands (in terminal) noted at the end of the previous output:<\/p>\n<pre><code class=\"language-bash\">cd pokemon_search_react\nnpm start<\/code><\/pre>\n<p>You should get this something similar to this output:<\/p>\n<pre><code class=\"language-bash\"> Compiled successfully!\n\nYou can now view pokemon_search_react in the browser.\n\n  Local:            http:\/\/localhost:3001\n  On Your Network:  http:\/\/192.168.8.165:3001\n\nNote that the development build is not optimized.\nTo create a production build, use npm run build.\n\nwebpack compiled successfully\nOne of your dependencies, babel-preset-react-app, is importing the\n&quot;@babel\/plugin-proposal-private-property-in-object&quot; package without\ndeclaring it in its dependencies. This is currently working because\n&quot;@babel\/plugin-proposal-private-property-in-object&quot; is already in your\nnode_modules folder for unrelated reasons, but it may break at any time.\n\nbabel-preset-react-app is part of the create-react-app project, which\nis not maintianed anymore. It is thus unlikely that this bug will\never be fixed. Add &quot;@babel\/plugin-proposal-private-property-in-object&quot; to\nyour devDependencies to work around this error. This will make this message\ngo away.<\/code><\/pre>\n<p>\u26a0\ufe0f If you&#8217;re bothered by the seeming error-like output, then just add the following code to your <code>package.json<\/code> file:<\/p>\n<pre><code class=\"language-javascript\">&quot;devDependencies&quot;: {\n  &quot;@babel\/plugin-proposal-private-property-in-object&quot;: &quot;^7.16.7&quot;\n},<\/code><\/pre>\n<p>You should see the following page in your browser if you open <a href=\"http:\/\/localhost:3001\">http:\/\/localhost:3001<\/a>. Please note that the port (number after <code>localhost:<\/code>) could be different. Usually it&#8217;s 3000, but I had some other stuff running at that port, so it took the next available one.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/GMFzt7r.png\" alt=\"\" \/><\/p>\n<h2>Folder structure<\/h2>\n<p>Now, let&#8217;s open this project in the editor of your choice (I&#8217;m using <a href=\"https:\/\/code.visualstudio.com\/\">Visual Studio Code<\/a>), and you should see something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/bAjDQhF.png\" alt=\"\" \/><\/p>\n<p>\u26a0\ufe0f This is an introduction tutorial, to get you running fast, so I won&#8217;t be going into any specific details and will be only focusing on the <code>src<\/code> folder.<\/p>\n<h2>Add content<\/h2>\n<p>OK, so let&#8217;s add something to our app.<\/p>\n<p>But, where to start? \ud83e\udd14<\/p>\n<p>Well, one of the first things I do when I come to a project for the first time is to look at the generated output. Then I try to find the strings corresponding to that output within the source code.<\/p>\n<p>So, if you search for the string <code>Learn React<\/code>, you&#8217;ll see the string is within the <code>App.js<\/code> file. This file contains the following code:<\/p>\n<pre><code class=\"language-javascript\">import logo from &#039;.\/logo.svg&#039;;\nimport &#039;.\/App.css&#039;;\n\nfunction App() {\n  return (\n    &lt;div className=&quot;App&quot;&gt;\n      &lt;header className=&quot;App-header&quot;&gt;\n        &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; \/&gt;\n        &lt;p&gt;\n          Edit &lt;code&gt;src\/App.js&lt;\/code&gt; and save to reload.\n        &lt;\/p&gt;\n        &lt;a\n          className=&quot;App-link&quot;\n          href=&quot;https:\/\/reactjs.org&quot;\n          target=&quot;_blank&quot;\n          rel=&quot;noopener noreferrer&quot;\n        &gt;\n          Learn React\n        &lt;\/a&gt;\n      &lt;\/header&gt;\n    &lt;\/div&gt;\n  );\n}\n\nexport default App;<\/code><\/pre>\n<p>Without knowing much about React, you can see where you would change the <code>Learn React<\/code> text. So, let&#8217;s change that to <code>Welcome to Pokemon Search<\/code>. Save that, and voila!, you&#8217;ll see the change reflected immediately in your browser.<\/p>\n<p>If you&#8217;re new to web dev, you may not appreciate the usefulness of the so-called hot-reload. Back in the day, we had to refresh the browser after each save. Yeah, yeah, I know: #okboomer \ud83e\udee3<\/p>\n<h2>Add some style<\/h2>\n<p>I borrowed the image (hope they don&#8217;t mind) from <a href=\"https:\/\/en.wikipedia.org\/wiki\/Pok%C3%A9mon\">Wikipedia<\/a> and saved it in the <code>src<\/code> folder as <code>logo.png<\/code>, added a search input, and styled it a bit to match it with the Pokemon style. <em>In case you&#8217;re wondering, I asked ChatGPT to help with coming up with the style<\/em> \ud83d\ude42<\/p>\n<p>Here&#8217;s the final code that I came up with in <code>App.js<\/code>:<\/p>\n<pre><code class=\"language-js\">import logo from &#039;.\/logo.png&#039;;\nimport &#039;.\/App.css&#039;;\n\nfunction App() {\n  return (\n    &lt;div className=&quot;App&quot;&gt;\n      &lt;header&gt;\n        &lt;img alt=&quot;react logo&quot; className=&quot;logo&quot; src={logo} \/&gt;\n      &lt;\/header&gt;\n\n      &lt;main&gt;\n        &lt;div className=&quot;search-container&quot;&gt;\n          &lt;input className=&quot;search-box&quot; type=&quot;text&quot; placeholder=&quot;Search...&quot; \/&gt;\n        &lt;\/div&gt;\n      &lt;\/main&gt;\n    &lt;\/div&gt;\n  );\n}\n\nexport default App;<\/code><\/pre>\n<p>And the CSS in the <code>App.css<\/code> file:<\/p>\n<pre><code class=\"language-css\">body {\n  background: linear-gradient(to right, #FDDF3C, #3B4CCA);\n}\n\nheader {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n}\n\n.logo {\n  margin: 0 2rem 0 0;\n}\n\n.search-container {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n  gap: 10px;\n}\n\n.search-box {\n  width: 30%;\n  height: 50px;\n  font-size: 1.5em;\n  padding: 10px;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  margin: 40px 0;\n  text-align: center;\n}<\/code><\/pre>\n<p>The way this looks now is as follows: <img decoding=\"async\" src=\"https:\/\/i.imgur.com\/hrX5ZR6.png\" alt=\"\" \/><\/p>\n<p><em>If you get stuck in any of the above steps, please reach out in the comments, and I&#8217;ll be happy to help.<\/em><\/p>\n<h2>Pokemon API<\/h2>\n<p>Finally, we come to the cool part \ud83e\udd76, and that is to fetch some data from the PokeAPI and show it in our app.<\/p>\n<p>How do we get this API? Well, if you do a simple Google search for <code>pokemon api<\/code> and open the <a href=\"https:\/\/pokeapi.co\/\">first link<\/a>, you&#8217;ll also get to the <a href=\"https:\/\/pokeapi.co\/docs\/v2\">documentation<\/a> for their API.<\/p>\n<p>By looking at the docs, you can find that the API endpoint that lists all the available Pokemon is this: <a href=\"https:\/\/pokeapi.co\/api\/v2\/pokemon\">https:\/\/pokeapi.co\/api\/v2\/pokemon<\/a>. There&#8217;s a total of 1302 records.<\/p>\n<p>Now, fetching all this data every time you load your app would be a bad idea from the performance standpoint, but also from their <a href=\"https:\/\/pokeapi.co\/docs\/v2#fairuse\">fair use<\/a> policy.<\/p>\n<p>So, what we will do is open <a href=\"https:\/\/pokeapi.co\/api\/v2\/pokemon?limit=1320\">this link<\/a> which will fetch all 1320 Pokemon endpoints. The output looks like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/BlKuxTW.png\" alt=\"\" \/><\/p>\n<p>Now, save this output (just Command + S or Ctrl + s if you&#8217;re on Windows) to a local file that we&#8217;ll name <code>pokemonapi.json<\/code> and place it in the <code>src\/<\/code> folder.<\/p>\n<blockquote>\n<p>\u26a0\ufe0f I just want to give proper props to <a href=\"https:\/\/pokeapi.co\/\">PokeAPI<\/a> for their awesome service \ud83d\udc4f<\/p>\n<\/blockquote>\n<p><em>For our demo purposes, this will be fine, but if you&#8217;d like to deploy this somewhere where you&#8217;d get a lot of traffic (or, if the main list of Pokemon changes), you&#8217;d have to cache the responses. We&#8217;ll tackle this in another blog post, but just something to keep in mind.<\/em><\/p>\n<h2>Show the data<\/h2>\n<p>Now we&#8217;ll want to list all the Pokemon that we have in the <code>pokemonapi.json<\/code> file. To do that, we&#8217;ll add some code at the top of the <code>App.js<\/code> file that looks like this:<\/p>\n<pre><code class=\"language-javascript\">import pokemonData from &quot;.\/pokemonapi.json&quot;;\nimport React, { useState } from &quot;react&quot;;<\/code><\/pre>\n<p>And then, inside the <code>function App()<\/code>:<\/p>\n<pre><code class=\"language-javascript\">  const [pokemonList, setPokemonList] = useState(pokemonData.results);\n  const [searchTerm, setSearchTerm] = useState(&quot;&quot;);\n  const [selectedPokemon, setSelectedPokemon] = useState(null);\n\n  const filteredPokemonList = pokemonList.filter((pokemon) =&gt;\n    pokemon.name.includes(searchTerm)\n  );<\/code><\/pre>\n<p><code>filteredPokemonList<\/code> function returns the list of pokemon that we loaded from the <code>pokemonapi.json<\/code> file and filters them by what we enter in the input box.<\/p>\n<p>We&#8217;ll add this portion of JSX just below the <code>search-container<\/code> div:<\/p>\n<pre><code class=\"language-JSX\">&lt;ul&gt;\n  {filteredPokemonList.map((pokemon) =&gt; (\n    &lt;li key={pokemon.id} className=&quot;pokemon-item&quot;&gt;\n      &lt;a href=&quot;#&quot;&gt;{pokemon.name}&lt;\/a&gt;\n    &lt;\/li&gt;\n  ))}\n&lt;\/ul&gt;<\/code><\/pre>\n<p>And, we&#8217;ll add a bit of CSS:<\/p>\n<pre><code class=\"language-css\">.pokemon-item {\n  float: left;\n  margin: 10px;\n}\n.pokemon-item a {\n  color: #000;\n  text-decoration: none;\n  font-size: 16px;\n  transition: color 0.3s ease;\n  text-transform: capitalize;\n}\n\n.pokemon-item a:hover {\n  color: #3B4CCA;\n}\n\nul {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n  gap: 5px;\n  list-style: none;\n}<\/code><\/pre>\n<p>Doing this, you should have your app look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/9CtWoYV.png\" alt=\"\" \/><\/p>\n<h2>Get additional details about each Pokemon<\/h2>\n<p>If you open any of the URLs that you see in the <code>pokemonapi.json<\/code> file, you will get an output like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/0e52ATX.png\" alt=\"\" \/><\/p>\n<p>To show some additional information about a certain Pokemon (once clicked on its name in the list), we&#8217;ll update the <code>a<\/code> tag inside the <code>li<\/code>:<\/p>\n<pre><code class=\"language-JSX\">&lt;li key={pokemon.id} className=&quot;pokemon-item&quot;&gt;\n  &lt;a href=&quot;#&quot; onClick={() =&gt; showPokemon(pokemon.url)}&gt;{pokemon.name}&lt;\/a&gt;\n&lt;\/li&gt;<\/code><\/pre>\n<p>On the click event we attached the <code>showPokemon<\/code> function (by using <code>onClick<\/code>) and passed it the URL that we get in the main API call (loaded from the JSON file).<\/p>\n<p>Now we should define this function:<\/p>\n<pre><code class=\"language-JS\">const showPokemon = async (url) =&gt; {\n  const response = await fetch(url);\n  if (!response.ok) {\n    console.error(`Error fetching Pokemon: ${response.statusText}`);\n    return;\n  }\n\n  const data = await response.json();\n  setSelectedPokemon(data);\n}<\/code><\/pre>\n<p>To show the selected Pokemon, we&#8217;ll add a bit of JSX between the <code>search-container<\/code> div and the <code>ul<\/code>:<\/p>\n<pre><code class=\"language-JSX\">{selectedPokemon &amp;&amp; (\n  &lt;div className=&quot;pokemon-details&quot;&gt;\n    &lt;h2&gt;{selectedPokemon.name}&lt;\/h2&gt;\n    &lt;img\n      src={selectedPokemon.sprites.front_default}\n      alt={selectedPokemon.name}\n    \/&gt;\n    &lt;p&gt;Height: {selectedPokemon.height}&lt;\/p&gt;\n    &lt;p&gt;Weight: {selectedPokemon.weight}&lt;\/p&gt;\n\n    {selectedPokemon.stats.map((stat, index) =&gt; (\n      &lt;div key={index}&gt;\n        &lt;p&gt;\n          {stat.stat.name}: {stat.base_stat}\n        &lt;\/p&gt;\n      &lt;\/div&gt;\n    ))}\n  &lt;\/div&gt;\n)}<\/code><\/pre>\n<p>We&#8217;re using <code>selectedPokemon &amp;&amp;<\/code> so that the line <code>{{ selectedPokemon.name }}<\/code> doesn&#8217;t throw an error for trying to access a property that doesn&#8217;t exist on the object <code>selectedPokemon<\/code> (which is initialized as <code>null<\/code> in the beginning: <code>const [selectedPokemon, setSelectedPokemon] = useState(null);<\/code>).<\/p>\n<p>BTW, <code>useState<\/code> is a so-called React Hook that essentially enables you to update a certain variable.<\/p>\n<p>Anyways, back on point; we&#8217;re using <code>map<\/code> to loop through all the elements of the <code>stats<\/code> array and output the <code>name<\/code> and <code>base_stat<\/code> properties.<\/p>\n<p>To make it look nicer, we&#8217;ll use a bit of CSS:<\/p>\n<pre><code class=\"language-CSS\">.pokemon-details {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  width: 30%;\n  margin: 20px auto;\n  padding: 20px;\n  border: 1px solid #000;\n  border-radius: 10px;\n  color: #000;\n  text-transform: capitalize;\n}\n\n.pokemon-details img {\n  width: 100px;\n  height: 100px;\n}<\/code><\/pre>\n<h2>Two-way data binding<\/h2>\n<p>Right now if you test your app and type something in the search box, it will <strong>not<\/strong> filter the list of Pokemon.<\/p>\n<p>You may remember that in Vue.js, we achieved this by using the <code>v-model<\/code>. However, in React, there isn&#8217;t a direct equivalent to Vue&#8217;s <code>v-model<\/code> for two-way data binding. In React we can achieve a similar effect by using a combination of state and event handlers.<\/p>\n<p>To do this, we&#8217;ll update the <code>input<\/code> tag to this:<\/p>\n<pre><code class=\"language-HTML\">&lt;input className=&quot;search-box&quot; type=&quot;text&quot;\n  placeholder=&quot;Search...&quot; \n  value={searchTerm} \n  onChange={event =&gt; setSearchTerm(event.target.value)}\n\/&gt;<\/code><\/pre>\n<p>In this code, <code>searchTerm<\/code> is a state variable that is set as the value of the input field. The <code>onChange<\/code> event handler updates <code>searchTerm<\/code> whenever the user types something into the input field. This creates a two-way data binding effect similar to Vue&#8217;s v-model.<\/p>\n<p>Go try it out! The app is now fully functional \ud83d\udcaa<\/p>\n<h2>All the code<\/h2>\n<p>For reference, for those following the tutorial to the dot, here&#8217;s the full listing of <code>App.js<\/code> file:<\/p>\n<pre><code class=\"language-JSX\">import logo from &quot;.\/logo.png&quot;;\nimport &quot;.\/App.css&quot;;\nimport pokemonData from &quot;.\/pokemonapi.json&quot;;\nimport React, { useState } from &quot;react&quot;;\n\nfunction App() {\n  const [pokemonList, setPokemonList] = useState(pokemonData.results);\n  const [searchTerm, setSearchTerm] = useState(&quot;&quot;);\n  const [selectedPokemon, setSelectedPokemon] = useState(null);\n\n  const filteredPokemonList = pokemonList.filter((pokemon) =&gt;\n    pokemon.name.includes(searchTerm)\n  );\n\n  const showPokemon = async (url) =&gt; {\n    const response = await fetch(url);\n    if (!response.ok) {\n      console.error(`Error fetching Pokemon: ${response.statusText}`);\n      return;\n    }\n\n    const data = await response.json();\n    setSelectedPokemon(data);\n  };\n\n  return (\n    &lt;div className=&quot;App&quot;&gt;\n      &lt;header&gt;\n        &lt;img alt=&quot;react logo&quot; className=&quot;logo&quot; src={logo} \/&gt;\n      &lt;\/header&gt;\n\n      &lt;main&gt;\n        &lt;div className=&quot;search-container&quot;&gt;\n          &lt;input className=&quot;search-box&quot; type=&quot;text&quot; placeholder=&quot;Search...&quot; \n          value={searchTerm} \n          onChange={event =&gt; setSearchTerm(event.target.value)}\n          \/&gt;\n        &lt;\/div&gt;\n\n        {selectedPokemon &amp;&amp; (\n          &lt;div className=&quot;pokemon-details&quot;&gt;\n            &lt;h2&gt;{selectedPokemon.name}&lt;\/h2&gt;\n            &lt;img\n              src={selectedPokemon.sprites.front_default}\n              alt={selectedPokemon.name}\n            \/&gt;\n            &lt;p&gt;Height: {selectedPokemon.height}&lt;\/p&gt;\n            &lt;p&gt;Weight: {selectedPokemon.weight}&lt;\/p&gt;\n\n            {selectedPokemon.stats.map((stat, index) =&gt; (\n              &lt;div key={index}&gt;\n                &lt;p&gt;\n                  {stat.stat.name}: {stat.base_stat}\n                &lt;\/p&gt;\n              &lt;\/div&gt;\n            ))}\n          &lt;\/div&gt;\n        )}\n\n        &lt;ul&gt;\n          {filteredPokemonList.map((pokemon) =&gt; (\n            &lt;li key={pokemon.id} className=&quot;pokemon-item&quot;&gt;\n              &lt;a href=&quot;#&quot; onClick={() =&gt; showPokemon(pokemon.url)}&gt;\n                {pokemon.name}\n              &lt;\/a&gt;\n            &lt;\/li&gt;\n          ))}\n        &lt;\/ul&gt;\n      &lt;\/main&gt;\n    &lt;\/div&gt;\n  );\n}\n\nexport default App;<\/code><\/pre>\n<p>And here&#8217;s the full contents of the <code>App.css<\/code> file:<\/p>\n<pre><code class=\"language-css\">body {\n  background: linear-gradient(to right, #FDDF3C, #3B4CCA);\n}\n\nheader {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n}\n\n.logo {\n  margin: 0 2rem 0 0;\n}\n\n.search-container {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n  gap: 10px;\n}\n\n.search-box {\n  width: 30%;\n  height: 50px;\n  font-size: 1.5em;\n  padding: 10px;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  margin: 40px 0;\n  text-align: center;\n}\n\n.pokemon-item {\n  float: left;\n  margin: 10px;\n}\n.pokemon-item a {\n  color: #000;\n  text-decoration: none;\n  font-size: 16px;\n  transition: color 0.3s ease;\n  text-transform: capitalize;\n}\n\n.pokemon-item a:hover {\n  color: #3B4CCA;\n}\n\nul {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n  gap: 5px;\n  list-style: none;\n}\n\n.pokemon-details {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  width: 30%;\n  margin: 20px auto;\n  padding: 20px;\n  border: 1px solid #000;\n  border-radius: 10px;\n  color: #000;\n  text-transform: capitalize;\n}\n\n.pokemon-details img {\n  width: 100px;\n  height: 100px;\n}\n\n.pokemon-details p {\n  margin: 5px;\n}<\/code><\/pre>\n<h2>B e a utiful<\/h2>\n<p>At this point, we can search for some Pokemon (my son&#8217;s favorite is, ofc, Pikachu), and if we click on it, we&#8217;ll get this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/DEWVNg7.png\" alt=\"search results - pikachu\" \/><\/p>\n<h2>Deployment<\/h2>\n<p>If you&#8217;d like to host this on your web server, then first run <code>npm run build<\/code> and you&#8217;ll get an output similar to this:<\/p>\n<pre><code class=\"language-bash\">> pokemon_search_react@0.1.0 build\n> react-scripts build\n\nCreating an optimized production build...\nCompiled with warnings.\n\n[eslint] \nsrc\/App.js\n  Line 64:15:  The href attribute requires a valid value to be accessible. Provide a valid, navigable address as the href value. If you cannot provide a valid href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https:\/\/github.com\/jsx-eslint\/eslint-plugin-jsx-a11y\/blob\/HEAD\/docs\/rules\/anchor-is-valid.md  jsx-a11y\/anchor-is-valid\n\nSearch for the keywords to learn more about each warning.\nTo ignore, add \/\/ eslint-disable-next-line to the line before.\n\nFile sizes after gzip:\n\n  58.34 kB (-1 B)  build\/static\/js\/main.b3bd969c.js\n  1.78 kB          build\/static\/js\/453.bd7a2879.chunk.js\n  677 B            build\/static\/css\/main.af098727.css\n\nThe project was built assuming it is hosted at \/.\nYou can control this with the homepage field in your package.json.\n\nThe build folder is ready to be deployed.\nYou may serve it with a static server:\n\n  serve -s build\n\nFind out more about deployment here:\n  https:\/\/cra.link\/deployment<\/code><\/pre>\n<p>Now all you have to do is take the contents of the <code>build<\/code> folder (you may remember that in Vue that folder was called <code>dist<\/code>) and &#8216;paste&#8217; it on your static web server.<\/p>\n<p>If you don&#8217;t have a server of your own, then Vite has an extensive <a href=\"https:\/\/vitejs.dev\/guide\/static-deploy\">description<\/a> for deploying your static pages to many popular services like Github Pages, Netlify, Vercel, Surge, etc.<\/p>\n<p>You can deploy to Github Pages in under 2 minutes by following their <a href=\"https:\/\/pages.github.com\/\">documentation<\/a>.<\/p>\n<p>Just for brevity sake the steps are as follows:<\/p>\n<ul>\n<li>create a new public Github repository and name it <code>username.github.io<\/code>, where <code>username<\/code> is your <code>username<\/code> on GitHub.<\/li>\n<li>clone the repo with <code>git clone https:\/\/github.com\/username\/username.github.io<\/code><\/li>\n<li>inside the folder copy the contents of the <code>build<\/code> folder<\/li>\n<li>commit and push the changes:<\/li>\n<\/ul>\n<pre><code class=\"language-bash\">git add --all \ngit commit -m &quot;Initial commit&quot;\ngit push -u origin main<\/code><\/pre>\n<p>Now your site will be visible online at <a href=\"https:\/\/username.github.io\">https:\/\/username.github.io<\/a> (again, where <code>username<\/code> is your Github username)<\/p>\n<p>You can see my deployment live <a href=\"https:\/\/hitman666.github.io\/pokemon-search-react\/\">here<\/a>.<\/p>\n<p>\u26a0\ufe0f If you&#8217;ll have multiple folders in Github pages, then before using the <code>npm run build<\/code> command, you&#8217;ll want to set the <code>homepage<\/code> variable in the <code>package.json<\/code> file to that folder. Example: <code>&quot;homepage&quot;: &quot;\/pokemon-search-react&quot;<\/code>.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this tutorial, you learned how to get started with using React by building an application for searching Pokemon by using PokeAPI and making it publically accessible via Github Pages.<\/p>\n<p>I intend to cover at least two more frameworks in the future blog posts, so stay tuned. Finally, out of curiosity, which one do you prefer so far: React or Vue.js? I&#8217;m looking to test Svelte next, but curious which one you&#8217;d like to see me cover.<\/p>\n<p>Please leave any comments and feedback in the discussion section below, and thank you for reading!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR In the previous tutorial I showed you how to get started with Vue.js 3 by building a Pokemon search application. I&#8217;m going to do the same here,&hellip;<\/p>\n","protected":false},"author":1,"featured_media":4673,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[63],"tags":[],"class_list":["post-4672","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-react"],"_links":{"self":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/4672","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/comments?post=4672"}],"version-history":[{"count":0,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/4672\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media\/4673"}],"wp:attachment":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media?parent=4672"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/categories?post=4672"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/tags?post=4672"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}