'How to use Axios with Vue 3 Composition API
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>
Solution 1:[1]
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/[email protected]/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>
Solution 2:[2]
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>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | chen chen |