繁体   English   中英

当商店中的状态更新时,Vue组件不会更新

[英]Vue component doesn't update when state in store is updated

我试图在Vue中创建一个简单的待办事项清单,但我想抽象出所有内容并使用虚拟的REST API,这样我就可以开始习惯于Vue中的生产级项目,这一切都使我很头疼。 GET,PUT和POST请求似乎可以正常工作,但是当我对后端执行成功的POST请求时,我无法弄清楚为什么待办事项列表不会自动更新。

我有一个TodoList组件,该组件遍历todosFiltered()计算属性以显示todosFiltered() 计算出的属性返回到Vuex存储中的getter todosFiltered 我还使用此处的created()生命周期钩子在商店中调度一个操作,该操作发出初始GET请求,然后在首次加载页面时在商店中填充一个称为todos的数组。 存储todosFiltered中的getter todosFiltered返回state.todos ,因此我假设当我的组件重新渲染时,它将具有从todosFiltered抓取的状态中的新todos数组,只有这种情况没有发生。 我在这里想念什么? 任何建议将不胜感激。

TodoList.vue

(我知道我必须为id设计一个解决方案,它在我的列表上: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)
            })
        },
    }
})

编辑:这是发生了什么事情在Vue的开发工具,当我加入待办事项- todos在店内的状态将立即被更新,并且todosFiltered在计算财产TodoList分量也反映了-但新的待办事项不会出现在列出! 奇怪。

问题是在v-for循环上使用了$ store.getter。 请尝试以下操作:

  1. 设置您的计算为

    todos(){返回this。$ store.todos; }

  2. 更改v-for循环以在待办事项中使用待办事项

  3. 将v-if条件添加到循环中,例如v-if =“ filtered(todo)”
  4. 创建一个称为filtered(或您喜欢的任何一种)的新方法,并在其中添加“ filteredTodos”逻辑,根据需要返回true / false
  5. 如果您需要共享此代码,则始终可以使用mixin并在组件之间共享

希望这对你有用

解决此问题的一种方法可以是创建我喜欢调用的refresh()方法。

基本上,你将有一个本地列表todosdata()方法中, refresh()方法将所有负载todos从商店到本地todos列表,每次你做一个动作时,如创建,删除或更新后,您将调用refresh方法为您重新加载列表。

因此,在您的TodoList.vue

<template>
    <todo-item v-for="todo in todosFiltered" :key="todo.id"></todo-item>
</template>

<script>
export default {
    data() {
        return {
            // Where we store the local list of Todos 
            // so the component will react when we do something to it
            todosFiltered: []
        }
    },
    methods {
        refresh() {
            // Get the todo list from the store.
            // which in turn will trigger a change event so the component
            // react to what we did.
            this.todosFiltered = this.$store.getters.todosFiltered;
        },
        addTodo() {
            this.$store.dispatch('addTodo').then(() => {
                // Refresh the list after adding a new Todo
                this.refresh();
            })
        },
        updateTodo() {
            this.$store.dispatch('updateTodo').then(() => {
                // Refresh the list after updating a Todo
                this.refresh();
            })
        },
        deleteTodo() {
            this.$store.dispatch('deleteTodo').then(() => {
                // Refresh the list after deleting a Todo
                this.refresh();
            })
        }
    },
    created() {
        this.$store.dispatch('loadTodos').then( () => {
            // Refresh the list when first loaded after the Todos been saved in Vuex
            this.refresh();
        })
    }
}
</script>

实际上,不要删除已有的东西,而要用它替换,只需将此处的内容应用于代码即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM