Vuex: Getter is not fetching data from external API - javascript

I'm trying to fetch data from an external API and display the data in my component but it is returning an empty array when I actually have data in my API.
Inside my module I have the following:
import axios from 'axios';
const state = {
countries = []
}
const getters = {
allCountries: (state) => state.countries;
}
const actions = {
//Fecth all the countries from the API
async fetchCountries({ commit }) {
const response = await axios.get('URL');
commit('setCountries', response.data);
},
}
const mutations = {
setCountries: (state, countries) => (state.countries = countries),
}
export default {
state,
getters,
actions,
mutations,
};
Component:
<template>
<div v-for="country in allCountries" :key="country.id">
<small>{{country.name}}</small>
</div>
</template>
<script>
import { mapGetters} from 'vuex';
export default{
name: 'CompCountry',
computed: mapGetters(['allCountries'])
}
</script>

You're missing to dispatch the action, to do that you should run it in a life cycle hook like mounted :
<template>
<div v-for="country in allCountries" :key="country.id">
<small>{{country.name}}</small>
</div>
</template>
<script>
import { mapGetters} from 'vuex';
export default{
name: 'CompCountry',
computed:{ ...mapGetters(['allCountries']},
mounted(){
this.$store.dispatch('fetchCountries')
}
}
</script>

Related

data from api can't assign to property in state

My project has /store.index.ts. I want to get data from api in actions block. I got data but can't assign data to property in state. I used interface because project has typescript and i used vuexStore. I wanted to work the axios.get in vuex store then i can't assign data to property of state .
/store/index.ts page:
import { createStore } from "vuex";
import axios from "axios";
export interface State {
tasks: any;
}
export default createStore<State> {
state: {
tasks: [],
},
getters: {
getAd(state) {
return state.tasks;
},
},
mutations: {
setTasks: (state, tasks) => {
state.tasks = tasks;
},
},
actions: {
async fetchProfile({ commit }) {
const response = await axios.get(
"https://5dd471358b5e080014dc51d2.mockapi.io/users/"
);
commit("setTasks", response.data);
return response.data;
},
},
modules: {},
};
newcomponent.vue page:
<template>
<div>
<h1>B12 Interactive</h1>
<div>
<h2>Skill Rating System</h2>
</div>
<div><input placeholder="Person/App/Rate" /></div>
<div>
<div class="vl"></div>
<hr />
<div class="v2"></div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { useStore } from "vuex";
export default defineComponent({
setup() {
const store = useStore();
const test = ref(
store.dispatch("fetchProfile")
); /*i can get data this line but
can't use with v:bind:key="item.id" in template block as v-for loop.This line is working in console.log() Array.length is higher than zero */
console.log(
"store:",
store.state.tasks
); /*i can't get data because data can't
assign to property in state. this line isn't working in console.log() Array.length is zero */
return {
test,
};
},
});
</script>

How to access props passed inside a setup function for Vuejs (Composition API)

When I use props to pass an object into the child component, I am unable to use the props inside the setup function (Composition API). I am trying to use the props to run a query from the firebase using the displayName property of the user instead of using 'Abe'. I am new to Vue, please help me out!
<template>
<div v-if="user">
<Process :user="user"/>
</div>
<div v-else>
<h1>Loading user</h1>
</div>
</template>
<script>
import Process from '../views/Process.vue'
import getUser from '#/composables/getUser'
export default {
components: { Process },
setup(){
const { user } = getUser();
return {user}
}
}
</script>
Using user in the setup function gives an undefined error but using it at top of the template returns the correct object.
<template>
<p>Process Payroll</p>
<h1>{{ user.displayName }} </h1>
<h1>{{ docs }} </h1>
</template>
<script>
// import getUser from '#/composables/getUser'
import { ref, onMounted, watch } from 'vue'
import { projectFirestore, projectAuth } from '#/firebase/config'
import { useRouter, useRoute } from 'vue-router'
export default {
props: ['user'],
setup() {
// const { user } = getUser();
// watch(()=> user, () => returnUser())
const lastName = ref("");
const firstName = ref("");
const docs = ref("");
const returnUser = async () => {
const res = await projectFirestore
.collection("users")
.where("displayName", "==", "Abe") // Case sensitive
.get();
const lastNameList = res.docs.map(d => `Abe ${d.data().lastName}`)
console.log(lastNameList)
console.log(user)
console.log(user.displayName)
docs.value = lastNameList;
}
onMounted(returnUser)
return { docs, returnUser};
},
}
</script>
Pass props to setup function:
setup(props) {
....

vue-query return ObjectRefImpl and not the data

vuejs community I'm a newbie on vue.js, to fetch data with vue-query, vue.js 3, and composition API, the returned data is ObjectRefImpl.
When I print the values It returns me: Property "isLoading" was accessed during render but is not defined on the instance.
So much thanks!
"vue": "^3.2.12",
"vue-query": "^1.11.0"
Todo.vue
import {onMounted} from 'vue';
export default {
setup() {
const fetcher = async () => {
await fetch('https://jsonplaceholder.typicode.com/todos').then(response =>
response.json()
);
};
onMounted(() => {
const {data, isError, error, isLoading} = useQuery('todos', fetcher);
console.log(data);
return {isLoading, isError, data, error};
});
}
};
App.vue
<script>
import {defineComponent} from 'vue';
import {useQueryProvider} from 'vue-query';
import {VueQueryDevTools} from 'vue-query/devtools';
export default defineComponent({
components: {VueQueryDevTools},
name: 'App',
setup() {
useQueryProvider();
}
});
</script>
<template>
<VueQueryDevTools :initialIsOpen="true" />
<router-view />
</template>
main.js
import {createApp} from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import './index.scss';
createApp(App)
.use(store)
.use(router)
.mount('#app');
You should make it work if you modify your component a little bit.
const fetcher = async () => {
await fetch('https://jsonplaceholder.typicode.com/todos').then(response =>
response.json()
);
};
export default {
setup() {
const {data, isError, error, isLoading} = useQuery('todos', fetcher);
console.log(data.value);
return {isLoading, isError, data, error};
}
};
All values returned by vue-query are refs, so you have to access them by accessing .value. This is due to Vue reactivity system, and it is necessary, so you can get automatic updates on those values.
Also you need to place your useQuery calls directly in setup. They will run and update whenever necessary without any action from your side.
You have a working example for this following this link: https://github.com/DamianOsipiuk/vue-query/tree/main/examples/simple

Vuex Mutation not updating the State

Working on a Vuejs application whereby I use Vuex for state management between the components.In Vuex store, I have an action that fetches some data from an API (which works fine) then populate it to the state (via a mutation). Next, I pass the updated state to the component using getters.
The problem is there is a problem populating data to the state from the action. In the DOM I have tried fetching via computed property or using the getter but get empty string
Vuex Store
const getDefaultState = () => {
return {
clientDeposit: ''
}
}
//state
const state = getDefaultState();
//getters
const getters = {
getDeposit: (state) => state.clientDeposit
}
//actions
const actions = {
fetchClients({ commit}) {
const clientId ="23"
axios.post('/api/motor/fetchClients', {
ClientId: clientId,
})
.then((response)=> {
//console.log(response); //returns data
const deposit = response.data;
commit('setIpfDeposit', deposit);
})
}
}
//mutations
const mutations = {
setIpfDeposit: (state, value) => (state.clientDeposit = value)
}
export default {
state,
getters,
actions,
mutations
}
Component
<template>
<div>
<button onclick="fetchClients()">Fetch Clients</button>
Deposit (Via computed property) : {{ fetchDeposit }}
Deposit (from getter) : {{ getDeposit }}
</div>
</template>
<script>
import { mapGetters , mapActions } from "vuex";
import axios from "axios";
export default {
name: "",
data() {
return {
}
},
computed: {
...mapGetters([
"getDeposit"
]),
fetchDeposit(){
return this.getDeposit
},
},
methods:{
...mapActions([
"fetchClients"
])
}
};
</script>
<style scoped>
</style>
You need to fetch the data first.
Import mapActions from vuex
import {mapActions, mapGetters} from 'vuex';
Bring in the fetchClients method in your component's methods object
methods:{
... mapActions(['fetchClients']),
}
Then in your component's created life cycle method call the fetchClients method
created(){
this.fetchClients();
}

vuex and axios debugging

I'm going crazy, I have a working api that sends data, I connected it to a VueJS app and it was working fine. I'm trying to implement Vuex and I'm stuck. Here's my store.js file
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios'
Vue.use(Vuex);
const state = {
message: "I am groot",
articles: []
}
const getters = {
getArticles: (state) => {
return state.articles;
}
}
const actions = {
getArticles: ({ commit }, data) => {
axios.get('/articles').then( (articles) => {
commit('GET_ARTICLES', articles);
console.log(articles); // Trying to debug
}, (err) => {
console.log(err);
})
}
}
const mutations = {
GET_ARTICLES: (state, {list}) => {
state.articles = list;
}
}
const store = new Vuex.Store({
state,
getters,
mutations,
actions,
mutations
});
console.log(store.state.articles); // this lines works but data is empty
export default store
The console.log within axios call doesn't run and store.state.articles is empty. I must be missing something. I'm just trying to console the articles data on page load...
Please help, I'm near insanity :)
Component :
<template>
<div class="container">
<h1>Test component yo !</h1>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
name: 'Test',
computed: {
message() {
return this.$store.state.message
}
},
mounted: () => {
this.$store.dispatch('getArticles')
}
}
</script>
App.js :
import Vue from 'vue';
import ArticlesViewer from './articles_viewer.vue';
import UserArticles from './user_articles.vue';
import App from './app.vue'
import store from './store'
new Vue({
el: '#app-container',
store,
render: h => h(App)
})
You define the mounted lifecycle hook of your component using an arrow function.
As per the documentation:
Don’t use arrow functions on an instance property or callback (e.g. vm.$watch('a', newVal => this.myMethod())). As arrow functions are bound to the parent context, this will not be the Vue instance as you’d expect and this.myMethod will be undefined.
You should define it like so:
mounted: function () {
this.$store.dispatch('getArticles');
}
Or, use the ECMAScript 5 shorthand:
mounted() {
this.$store.dispatch('getArticles');
}
Now, your dispatch method will be called correctly, populating your articles array.

Categories

Resources