【问题标题】:Lists and Components not updating after data change - (VueJS + VueX)数据更改后列表和组件不更新 - (VueJS + VueX)
【发布时间】:2017-11-30 15:49:13
【问题描述】:

关于最佳实践(甚至是首选实践)的问题

我有一个清单(例如待办事项清单)。我的实际做法是:

  • 在我的父组件上,我填充了我的“store.todos”数组。用一个 getter,我得到所有待办事项并使用 v-for 在列表上迭代 循环。

  • 每个项目都是一个组件,我将待办事项作为道具发送。

  • 在这个组件中,我有更新“完成”标志的逻辑。这个元素根据标志的“状态”显示一个复选框。当它这样做时,它会对数据库执行一个操作并更新存储状态。

我应该改为:

  • 让每个列表项都有一个 getter,并且只将 ID 发送到子组件?

一切正常,但是如果我将新项目添加到待办事项列表中,当我将其标记为已完成时,该项目不会更新。我想知道这个问题是否是因为我在子组件中使用了道具而不是吸气剂

代码:

商店

const state = {     
    tasks: []
}

const mutations = {     
CLEAR_TASKS (state) {
    state.tasks = [];
},
SET_TASKS (state, tasks) {
    state.tasks = tasks;
},
ADD_TASK (state, payload) {
    // if the payload has an index, it replaces that object, if not, pushes a new task to the array
    if(payload.index){          
        state.currentSpaceTasks[payload.index] = payload.task;
        // (1) Without this two lines, the item doesn't update
        state.tasks.push('');
        state.tasks.pop();
    }
    else{           
        state.tasks.push(payload.task);
    }
},
SET_TASK_COMPLETION (state, task){

    let index = state.tasks.findIndex(obj => obj.id == task.id);
    state.tasks[index].completed_at = task.completed_at;
}
}

const getters = {   
(...)
getTasks: (state) => (parentId) => {        
    if (parentId) {
        return state.tasks.filter(task => task.parent_id == parentId );
    } else {            
        return state.tasks.filter(task => !task.parent_id );
    }
}
(...)
}

const actions = {   
(...)
/*
* Add a new Task 
* 1st commit add a Temp Task, second updates the first one with real information (Optimistic UI - or a wannabe version of it)
*/
addTask({ commit, state }, task ) {         
        commit('ADD_TASK',{
            task
        });
    let iNewTask = state.currentSpaceTasks.length - 1;

axios.post('/spaces/'+state.route.params.spaceId+'/tasks',task).then(
        response => {
            let newTask = response.data;    
            commit('ADD_TASK',{
                task: newTask,
                index: iNewTask
            });
        },
        error => {
            alert(error.response.data);
        });

},
markTaskCompleted({ commit, dispatch, state }, task ){

        console.log(task.completed_at);
        commit('SET_TASK_COMPLETION', task);
        dispatch('updateTask', { id: task.id, field: 'completed', value: task.completed_at } ).then(
            response => {
                commit('SET_TASK_COMPLETION', response.data);
            },
            error => {
                task.completed_at = !task.completed_at;
                commit('SET_TASK_COMPLETION', task);
            });

},
updateTask({ commit, state }, data ) {              
    return new Promise((resolve, reject) => {       
        axios.patch('/spaces/'+state.route.params.spaceId+'/tasks/'+ data.id, data).then(
        response => {
            resolve(response.data);
        },
        error => {
            reject(error);      
        });
    })
}

}

基本上这是我的父子组件:

任务列表组件(它从 Getter 加载任务) (...)

    <task :task = 'item' v-for = "(item, index) in tasks(parentId)" :key = 'item.id"></task>            
(...)

任务组件显示一个“复选框”(使用 Fontawesome)。并根据已设置的 completed_at/true 在选中/未选中之间进行更改。

此程序运行良好:

  1. 访问任务列表
  2. 将一项现有项目标记为已完成 - 已选中复选框

此过程失败

  1. 添加一个新任务(它触发添加任务,它首先添加一个“临时”项目,然后在 ajax 返回后,用真实信息(id 等)更新它。虽然它没有id,任务显示加载而不是复选框,并在更新后显示复选框 - 这有效!
  2. 检查新添加的任务 - 它确实发送了请求,它更新了项目和数据库。但是复选框没有更新:(

【问题讨论】:

  • Getters 设计完全取决于您,我相信。关于最后一个问题 - 没有实际代码很难说。可能您没有为 v-for 元素分配唯一的 key 属性(如果您的意思是更新未反映在模板中)。
  • @wostex 今天早上我正在尝试,但没有运气,公平地说,因为我一开始没有得到这个概念,所以没有正确地做到这一点。今晚会检查一下,如果解决了,请告诉您!
  • 如果它不能解决您的问题 - 将您的相关代码部分添加到问题中,它有助于调试。
  • 您如何更新完成标志 - 您是否在商店中调用操作?
  • @wostex 添加了代码 - 试图删除所有不相关的信息以便更容易检查...有趣的是它适用于已经存在的项目

标签: vue.js vuex


【解决方案1】:

在 Vue.js 文档之间进行挖掘后,我可以修复它。

Vue.js 和 Vuex 不会将响应性扩展到不在原始对象上的属性。

例如,要在数组中添加新项目,您必须这样做:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)

更多信息在这里: https://vuejs.org/v2/guide/reactivity.html

这里:https://vuejs.org/v2/guide/list.html#Caveats

起初它只解决了部分问题。将项目推入数组后,我不需要使用“hack”(推并弹出一个空对象以强制重新加载列表)

但是现在考虑到这一点,我检查了服务器返回的对象,虽然在 getTasks 上,列表包含所有字段,包括已完成的_at,但在保存新项目后,它只返回了设置(完成时创建时为空)。这意味着 Vue.js 没有跟踪这个属性。

我添加了要由服务器端(Laravel,顺便说一句)返回的属性,现在一切正常!

如果有人对我的代码有其他意见,请随时添加:)

谢谢大家

【讨论】:

猜你喜欢
  • 2020-10-27
  • 2019-03-20
  • 2017-07-31
  • 2019-09-01
  • 2019-06-08
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 2019-02-18
相关资源
最近更新 更多