Reputation: 2711
I am trying to populate the data of a chart but first I have to get data to populate it. This data is inside my vuex state which uses an api request to get the data. But when I return this state its an empty array. How can I ensure that the data is set before I return it?
my vuex state;
import axios from 'axios';
const state = {
boardPosts: [],
boardColumnData: []
};
const actions = {
getAllBoardPostData: ({commit}) => {
function getBoardColumns() {
return axios.get('http://localhost:5000/api/summary-board/columns');
}
function getBoardPosts() {
return axios.get('http://localhost:5000/api/summary-board/posts');
}
axios.all([getBoardColumns(), getBoardPosts()])
.then(axios.spread((columnData, postData) => {
let rawPosts = postData.data;
let columns = columnData.data;
let posts = Array.from({length: columns.length}, ()=> []);
rawPosts.forEach((post) => {
// If column index matches post column index value
if(posts[post.column_index]){
posts[post.column_index].push(post);
}
});
columns.forEach((column, index) => {
let columnValue = 0;
posts[index].forEach((post) => {
columnValue += post.annual_value;
});
column.column_value = columnValue;
});
commit('setBoardColumns', columns);
commit('setBoardPosts', posts);
}))
.catch(error => console.log(error));
}
};
const mutations = {
setBoardPosts: (state, payload) => {
state.boardPosts = payload;
},
setBoardColumns: (state, payload) => {
state.boardColumnData = payload;
}
};
export default {
state,
actions,
mutations
};
in my vue file;
export default {
name: "Doughnut",
computed: {
boardColumns() {
return this.$store.state.Dashboard.boardColumnData;
}
},
created() {
this.populate();
},
methods: {
populate() {
console.log(this.boardColumns)
}
}
};
Upvotes: 0
Views: 1167
Reputation: 2073
You seem to be forgetting to actually dispatch the action to get the data. Try this in your created hook:
created() {
this.$store.dispatch('Dashboard', 'getAllBoardPostData');
this.populate();
}
EDIT:
Dispatching the action in another component is okay. In that case, the created hook might be too early in the lifecycle to wait for the data being fetched (since this component doesn't know about the one doing the dispatch), and it only runs once. You could add a watcher to wait for the computed property to change and trigger a side-effect (the populate method).
watch: {
boardColumns() {
this.populate()
}
}
Or, if the data is essential to render the component, you could consider using the data to determine a v-if
in the parent component as @Estus Flask suggested. Depending on how your component is structured in terms of reuse and tight coupling to the store, you could even pass it down as props at that point.
// Parent component.vue
<template>
<Doughnut
v-if="boardColumns && boardColumns.length"
:boardColumns="boardColumns"
/>
</template>
<script>
import Doughnut from './Doughnut.vue'
export default {
components: {
Doughnut,
},
computed: {
boardColumns() {
return this.$store.state.Dashboard.boardColumns
}
}
}
</script>
// Doughnut.vue
<template>
<div>
{{ boardColumns }}
</div>
</template>
<script>
export default {
name: "Doughnut",
props: {
boardColumns: {
type: Object,
required: true,
}
},
created() {
this.populate();
},
methods: {
populate() {
console.log(this.boardColumns)
}
}
};
</script>
Upvotes: 0
Reputation: 9390
Seeing your problem, you can setup a watcher on a Vuex store getter and perform your task once you get a value.
Define getter as
getters: {
getBoardData: state => state.boardColumnData
}
and map your getter and create a watcher as
computed: {
...mapGetters(['getBoardData'])
},
watch: {
getBoardData: {
immediate: true,
handler(to, from) {
if(to) {
//handle your changes
this.populate()
}
}
}
}
If you had the action dispatched in the same component, as actions are asynchronous, you could have chained a callback and called populate()
on completion.
Upvotes: 1
Reputation: 1554
This is a normal behaviour the component will render before the Vuex store
. When the computed section will check there won't be data initialised in the store
.
This could happen when you're using XHR
request to get the store
data.
The solution is to use v-if
condition where the computed
property is using. In your case you can check
v-if = "boardColumns.length>0"
Upvotes: 0