Trying to create a simple todo list in Vue, but aiming to abstract everything out and utilize a dummy REST API for practice with production-level Vue projects has left my head spinning. While GET, PUT, and POST requests appear to be functioning properly, I'm struggling to understand why the list of todos doesn't automatically update when a successful POST request is made to the backend.
The TodoList
component iterates through a computed property called todosFiltered()
to display the todos. This computed property references the todosFiltered
getter in the Vuex store. Additionally, the created()
lifecycle hook is used to dispatch an action in the store that executes the initial GET request and populates an array named todos
in the store upon the page's first load. The getter todosFiltered
within the store returns state.todos
, so I assumed that once the component re-renders, it would have the updated todos
array from the state obtained via todosFiltered
. However, this expected behavior is not occurring. Any insights or advice on what might be missing here are highly appreciated.
TodoList.vue
(Acknowledging that resolving the id issue is on my agenda :p)
<template>
<div class="container">
<input v-model="newTodo" type="text" placeholder="What must be done?" class="todo-input" @keyup.enter="addTodo">
<transition-group name="fade" enter-active-class="animated zoomIn" leave-active-class="animated zoomOut">
<todo-item v-for="todo in todosFiltered" :key="todo.id" :checkAll="!anyRemaining" :todo="todo"></todo-item>
</transition-group>
<div class="extra-container">
<todos-filtered></todos-filtered>
</div>
</div>
</template>
<script>
import TodosFiltered from './TodosFiltered'
import TodoItem from './TodoItem'
export default {
name: 'todolist',
components: {
TodosFiltered,
TodoItem
},
data() {
return {
beforeEditCache: '',
newTodo: '',
idForTodo: 10,
}
},
// Methods
methods: {
addTodo() {
if (this.newTodo.trim().length == 0) {
return
}
this.$store.dispatch('addTodo', {
id: this.idForTodo,
title: this.newTodo,
completed: false
})
this.newTodo = ''
this.idForTodo++
}
},
computed: {
todosFiltered() {
return this.$store.getters.todosFiltered
},
},
created() {
this.$store.dispatch('loadTodos')
},
}
</script>
store.js
export const store = new Vuex.Store({
state: {
filter: 'all',
todos: []
},
getters: {
todosFiltered(state) {
if (state.filter == 'all') {
return state.todos
} else if (state.filter == 'active') {
return state.todos.filter(todo => !todo.completed)
} else if (state.filter == 'completed') {
return state.todos.filter(todo => todo.completed)
}
return state.todos
},
showClearCompleted(state) {
return state.todos.filter(todo => todo.completed).length > 0
}
},
mutations: {
addTodo(state, todo) {
state.todos.push(todo)
},
setTodos(state, todos) {
state.todos = todos
},
},
actions: {
loadTodos(context) {
axios.get('http://localhost:3000/todos')
.then(r => r.data)
.then(todos => {
context.commit('setTodos', todos)
})
},
updateTodo(context, todo) {
axios.put('http://localhost:3000/todos/' + todo.id, {
"id": todo.id,
"title": todo.title,
"completed": todo.completed
})
},
addTodo(context, todo) {
axios.post('http://localhost:3000/todos', {
"id": todo.id,
"title": todo.title,
"completed": todo.completed
})
.then(todo => {
context.commit('addTodo', todo)
})
},
}
})
In Vue Dev Tools, upon adding a todo, todos
in the store's state is promptly updated, and the todosFiltered
computed property in the TodoList
component also mirrors this change. However, the new todo fails to appear in the list, presenting a peculiar situation.