Natural Pokedex Refactor
Tags: beginners, react
Published: 2019-04-01 17:13:58

---
title: Natural Pokedex Refactor
published: true
description: let's fix our errors!
tags: beginner, react
---

Project I'm Talking about: [Here](https://misnina.github.io/gnosis-pokedex/)
Original Article: {% link misnina/small-project-reflection-natural-pokedex-react-3oj8 %}

### What went wrong?

I feel a little embarrassed! It seems I was very much mismanaging and over pulling from the API in my last build. I was given a very informative comment on all the issues and I set out to attempt to address all of them.

{% devcomment 9n23 %}

### Starting from (almost) scratch

I realized I need to do all my information handling from the top most parent and pass down the attributes instead of letting the entry itself handle the data calling. The embarrassing part is that the comment doesn't reach the fact that the data call was *refetching everytime it reloaded the components*, which was every time you did a search. I don't know how I missed this really, I should have realized that having each component rerender on search was stupid, and honestly just wastes a lot of time.

So let's start using states, and only states! I can store all the information I gather from the top level, and **only** call the data to store once. The offset and limit were a good tip for other apis in the future, but unfortunately this pokedex isn't in a sorted listed in the api, and to sort by type I need to match against the data I've collected, not just which ever one is displaying at the time. Anyways, I decided to cut out the types, as it was the only attribute I was getting from the original dex entry, and not the species dex, so I also got to cut out that gross filter for my initial calls.

```javascript
fetchPokemon = (name, id) => {
    axios.get(`https://pokeapi.co/api/v2/pokemon-species/${name.toLowerCase()}/`)
      .then( res => {
        const info = res.data;
        let eggSecond;
        info.egg_groups[1] ?
          eggSecond = info.egg_groups[1].name : eggSecond = null;
        
        let enEntries = info.flavor_text_entries.filter(entry => {
          return entry.language.name === 'en'
        });
        const data = {
          name: name,
          id: id,
          color: info.color.name,
          eggGroups: [
            info.egg_groups[0].name,
            eggSecond,
          ],
          genus: info.genera[2].genus,
          shape: info.shape.name,
          flavorText: enEntries[0].flavor_text,
        }

        this.setState(prevState => {
          const allEntryInfo = [...prevState.allEntryInfo, data];
          return {allEntryInfo};
        });

        this.setState({ counter : this.state.counter + 1 })
      }).catch (err => console.log);
  }

}
```

###Fetch less

Since we'll be storing the data ourselves and calling upon it, might as well format it before we put it in. One thing about states is that they should be immutable, so I had some figuring out to do to do that, and I flailed around a bit to do it, but I think I get it now.

When you setState, you can instead pass a function with the current state's snapshot in time as a variable. So you set the new state to be an array of all previous entries, plus a new one with the data we've collected, then return that new setup for the setState to take in. The spread (...) was a tricky one when I first saw it, but it basically means that it can be zero or any number of items, which is handy! In addition to this, we have another state variable that counts up each time an entry is gone through.

Once we have our data, we can move on to actually rendering, and figuring out *when* to render. Because setState rerenders each time it's called, we're actually rerendering a blank page 200 times, which I don't know if it has actual performance issues, but it's somewhat annoying feeling. For this reason, we can edit our shouldComponentUpdate feature. 

```javascript
  shouldComponentUpdate() {
    if (this.state.counter >= 199) {
      return true;
    } else {
      return false;
    }
  
```

If the counter hits 199, then the component should update when it receives new props or states. Easy enough, now let's add on to our fetchPokemon call to make an object containing the JSX elements we need to render.

```javascript
const entry = <Entry
          id={id}
          name={name}
          key={name}
          color={data.color}
          egg1={data.eggGroups[0]}
          egg2={data.eggGroups[1]}
          genus={data.genus}
          shape={data.shape}
          flavorText={data.flavorText}
          setSorting={this.setSorting}
        />;
      this.setState(prevState => ({
        allEntryComponents: {
          ...prevState.allEntryComponents,
          [name] : entry
        }
      }))
```

###Out of Order

I make this an object with the name as a key for a reason. The reason is this.

![](https://thepracticaldev.s3.amazonaws.com/i/23lygwnzfwqgvejqra9x.PNG)

It really is true, the calls do get out of order and return at different times. This is a mess, but I don't know of a way to force them to go in order, and is it worth the wait? We can just sort them after, but for the components we need them to be named to know which pokemon is stored where as we can't access their id number once they're sorted as an element.

```javascript
  sortBy(type, value) {
    const { allEntryInfo, allEntryComponents } = this.state;
    let sorted = [];
    if (type === 'all') {
      GPOKEDEX.forEach(pokemon => {
        sorted.push(allEntryComponents[pokemon]);
      });
    } else if (type === "eggGroups") {
      let typeSorted = allEntryInfo.filter(pokemon => {
        return pokemon[type][0] === value || pokemon[type][1] === value ;
       });
       typeSorted
         .sort((a, b) => a.id - b.id)
         .forEach(pokemon => {
           sorted.push(allEntryComponents[pokemon.name])
         });
    } else {
      let typeSorted = allEntryInfo.filter(pokemon => {
       return pokemon[type] === value;
      });
      typeSorted
        .sort((a, b) => a.id - b.id)
        .forEach(pokemon => {
          sorted.push(allEntryComponents[pokemon.name])
        });
    }
    return sorted;
  }
```

While we're sorting by number, we can be smarter about how we do our searches for different types. First, for all, we just take the order from the GPOKEDEX listing, and push to the corresponding name in allEntryComponents. For the other ones, when setting the sortBy, we take arguments 'sortType and sortValue', meaning we want to do sortBy('color', 'green') for example. These are also stored in the top-level state, so the component rerenders when called, and also displays what you're looking at in the header. For egg groups, the only difference is that we OR compare two of the values, as they can match the first or second place.

While we are trying to sort the components, we use the info placement first so we can get at the inner data. We filter to only get the ones where the type matches the value set. One we have that, we call two things, sort and a forEach. Sort compares each entry with the other, and sees if the the id is higher or lower then each of them, and then returns them in proper order. So now we have our data, filtered by the type, and sorted by ID, but now we need the related components! For each element in the array, we push to the sorted array the corresponding entry component with the pokemon's name again.

Now we're getting somewhere!

![](https://thepracticaldev.s3.amazonaws.com/i/xsew1j0ukq2r7fgwuogp.PNG)

### Etc.

I had some troubles with a missing value, or rather a missing level in an object, so it was returning an object and React really doesn't like that, but can't pinpoint what line it's on so I had some time figuring it out. Since I had all the styling done, that's about it! Just had to reset a few things, and because react is react, I could just reuse a lot of components.

So now instead of an embarrassing amount of api calls (400 x whenever it reloaded), we call 200 for the entire limetime you are on the page. Also the searches are very fast because they're already loaded!

###What's next?

I still haven't been able to wrap my head around Redux, but I was seeing some stuff about sorting the information, possibly in local storage, so it wouldn't even need to recall that 200 until you cleared your data. I need to research a bit more about it.