How to use Axios with Vue 3 Composition API

Viewed 9060

I am attempting to build a Pokemon filtered search app with Vue 3 and Composition API based on the following tutorial: https://www.youtube.com/watch?v=QJhqr7jqxVo. (GitHub: https://github.com/ErikCH/PokemonVue)

The fetch method used in the search component includes a reduce() function to handle urlIdLookup based on a specific id assigned to each Pokemon in the API response:

    const state = reactive({
      pokemons: [],
      filteredPokemon: computed(()=> updatePokemon()), 
      text: "",
      urlIdLookup: {}
      
    });

    fetch("https://pokeapi.co/api/v2/pokemon?offset=0")
      .then((res) => res.json())
      .then((data) => {
        console.log(data);
        state.pokemons = data.results;
        state.urlIdLookup = data.results.reduce((acc, cur, idx)=> 
           acc = {...acc, [cur.name]:idx+1 }
        ,{})
        console.log('url',state.urlIdLookup+1)
        
      });

urlIdLookup is then passed into the route used to display selected Pokemon info:

    <div
      class="ml-4 text-2xl text-blue-400"
      v-for="(pokemon, idx) in filteredPokemon"
      :key="idx"
    >
      <router-link :to="`/about/${urlIdLookup[pokemon.name]}`">
        {{ pokemon.name }}
      </router-link>
    </div>

Instead of using the above fetch setup, I wish to use Axios to handle the request and response from the Pokemon API. After installing Axios in the project and importing it into the component, I added a new fetchPokemon method:

    const fetchPokemon = () => {
      axios.get('https://pokeapi.co/api/v2/pokemon?offset=0')
      .then(response => {
        state.pokemons = response.data
      })
    }

    onMounted(() => {
      fetchPokemon()
    })

While using Axios in this new fetch method, I want to handle urlIdLookup similar to the previous fetch setup, but without using the reduce() method and de-structured accumulator, if possible. How can I go about using Axios to retrieve the urlId of each Pokemon, then pass that urlId into the "about" route in the template?

Here is the full component:

<template>
<div class="w-full flex justify-center">
<input placeholder="Enter Pokemon here" type="text" 
    class="mt-10 p-2 border-blue-500 border-2" v-model="text" />

</div>

  <div class="mt-10 p-4 flex flex-wrap justify-center">

    
    <div
      class="ml-4 text-2xl text-blue-400"
      v-for="(pokemon, idx) in filteredPokemon"
      :key="idx"
    >
      <router-link :to="`/about/${urlIdLookup[pokemon.name]}`">
        {{ pokemon.name }}
      </router-link>
    </div>
  </div>
</template>

<script>
import axios from 'axios';
import { reactive, toRefs, computed, onMounted } from "vue";
export default {
  setup() {
    const state = reactive({
      pokemons: [],
      filteredPokemon: computed(()=> updatePokemon()), 
      text: "",
      urlIdLookup: {}
      
    });

    const fetchPokemon = () => {
      axios.get('https://pokeapi.co/api/v2/pokemon?offset=0')
      .then(response => {
        state.pokemons = response.data
      })
    }

    onMounted(() => {
      fetchPokemon()
    })

    // fetch("https://pokeapi.co/api/v2/pokemon?offset=0")
    //   .then((res) => res.json())
    //   .then((data) => {
    //     console.log(data);
    //     state.pokemons = data.results;
    //     state.urlIdLookup = data.results.reduce((acc, cur, idx)=> 
    //        acc = {...acc, [cur.name]:idx+1 }
    //     ,{})
    //     console.log('url',state.urlIdLookup+1)
        
    //   });

    function updatePokemon(){
      if(!state.text){
        return [] 
      }
      return state.pokemons.filter((pokemon)=> 
          pokemon.name.includes(state.text)
      )
    }

    return { ...toRefs(state), fetchPokemon, updatePokemon };
  }
};
</script>

2 Answers

it seem id is not necessary, why not use name be id. if you want use interger be must, you can foreach results set index be id to each item, then

 <router-link :to="`/about/${pokemon.id}`">
        {{ pokemon.name }}
      </router-link>

If I understood you correctly take a look at following snippet:

const { reactive, toRefs, computed, onMounted } = Vue
const { axioss } = axios
const app = Vue.createApp({
  setup() {
    const state = reactive({
      pokemons: [],
      filteredPokemon: computed(() => updatePokemon()),
      text: "",
      urlIdLookup: {},
    });

    const fetchPokemon = () => {
      axios
        .get("https://pokeapi.co/api/v2/pokemon?offset=0")
        .then((response) => {
          state.pokemons = response.data.results; //  get just results
        });
    };

    fetchPokemon();
  
    //  function to get index
    const getPokemonId = (item) => {
      return state.pokemons.findIndex((p) => p.name === item);
    };

    function updatePokemon() {
      if (!state.text) {
        return [];
      }
      return state.pokemons.filter((pokemon) =>
        pokemon.name.includes(state.text)
      );
    }
                                                        //  return new function
    return { ...toRefs(state), fetchPokemon, updatePokemon, getPokemonId };
  },
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3.2.29/dist/vue.global.prod.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.26.1/axios.min.js" integrity="sha512-bPh3uwgU5qEMipS/VOmRqynnMXGGSRv+72H/N260MQeXZIK4PG48401Bsby9Nq5P5fz7hy5UGNmC/W1Z51h2GQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div id="demo">
  <div class="w-full flex justify-center">
    <input
      placeholder="Enter Pokemon here"
      type="text"
      class="mt-10 p-2 border-blue-500 border-2"
      v-model="text"
    />
  </div>
  <div class="mt-10 p-4 flex flex-wrap justify-center">
    <div
      class="ml-4 text-2xl text-blue-400"
      v-for="(pokemon, i) in filteredPokemon"
      :key="i"
    >
                          <!-- //  call function to get index -->
      <router-link :to="`/about/${getPokemonId(pokemon.name)}`">
        {{ pokemon.name }} - id {{ getPokemonId(pokemon.name) }}
      </router-link>
    </div>
  </div>
</div>

Related