Reputation: 387
I'm trying to push task
to state.tasks
variable array in store module via mutation. When I'm fetching all tasks and assign it to a state.tasks
everything works perfect and appears on the screen, but when I'm pushing task
to a state.tasks
store is not adding it on a view.(I checked it via console.log task was pushed to state.tasks in mutation. No errors).
I've left info below. What am I doing wrong?
State:
const state = {
tasks: [],
};
Actions:
The tasks
is api service which I import import tasks from '../../api/tasks';
const actions = {
getTasks({commit}) {
return new Promise((resolve, reject) => {
tasks.getTasks().then(response => {
commit('setTasks', response.data.data);
resolve(response);
}).catch(error => {
reject(error);
})
});
},
createTask({commit}, text) {
return new Promise((resolve, reject) => {
tasks.createTask(text).then(response => {
commit('createTask', response.data.data);
resolve(response);
}).catch(error => {
reject(error);
})
});
}
};
Mutation:
const mutations = {
setTasks(state, tasks) {
state.tasks = tasks;
},
createTask(state, task) {
state.tasks.push(task);
console.log(state.tasks);
}
};
Getters:
const getters = {
undoneTasks(state) {
return state.tasks.filter(task => task.done == false);
},
doneTasks(state) {
return state.tasks.filter(task => task.done == true);
}
};
In component:
mounted() {
store.dispatch('getTasks').catch(error => {
if (error.response) {
this.checkResponse(error.response.status);
}
});
},
methods: {
createTask() {
store.dispatch('createTask', this.taskText)
.then(() => {
this.taskText = '';
}).catch(error => {
if (error.response) {
this.checkResponse(error.response.status);
}
});
}
},
computed: {
...mapGetters({
tasks: 'undoneTasks'
}),
},
Updated
In module actions tasks
is api service which I import import tasks from '../../api/tasks';
Also I tried to state.tasks.pop()
and It worked, I thought that is because of incorrect incoming data, but I checked again and it really pushing it to state.tasks but component does not react...
Upvotes: 4
Views: 1871
Reputation: 387
Ok, guys so I figured it out. Thanks for all support and answers. So I have tried manually set object for push in mutation.
createTask(state, task) {
const taskObj = {id: task.id, text: task.text, done: false};
state.tasks.push(taskObj);
}
And It worked, the problem was because of done
field that was coming as null from server. I think I should read more info about vuex, but it is very strange...
Upvotes: 1
Reputation: 5825
I would set tasks as an empty array to start with and only allow the createTask
mutation to add tasks to the array. I've recreated your code and it works fine, though I am not using the spread mapGetters
.
const store = new Vuex.Store({
state: {
tasks: [],
},
actions: {
createTask({commit}, task) {
return new Promise((res, rej) => {
setTimeout(() => {
commit('createTask', task);
res(true);
}, 1000);
});
},
},
mutations: {
createTask(state, task) {
state.tasks.push(task);
},
},
getters: {
undoneTasks: state => state.tasks.filter(t => t.done === false),
},
});
new Vue({
el: "#app",
store,
data: {
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
},
computed: {
tasks() {
return this.$store.getters.undoneTasks;
}
},
created() {
this.$store.dispatch('createTask', { text: "Learn JavaScript", done: false });
this.$store.dispatch('createTask', { text: "Learn Vue", done: false });
setTimeout(() =>
[{ text: "Play around in JSFiddle", done: false },
{ text: "Build something awesome", done: false }].map(t => this.$store.dispatch('createTask', t)), 1000);
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in tasks">
<label>
<input type="checkbox"
v-on:change="toggle(todo)"
v-bind:checked="todo.done">
<del v-if="todo.done">
{{ todo.text }}
</del>
<span v-else>
{{ todo.text }}
</span>
</label>
</li>
</ol>
</div>
Upvotes: 0