选择待办事项列表时TodoList组件未更新问题求助
TodoList组件未随状态更新的排查与解决
我有两个组件:TodoList和TodoListsList,分别从todos.js和todoLists.js模块的状态中获取数据。当选择某条待办事项列表并标记为活跃状态时,TodoListsList组件会正常更新,但TodoList组件却没有更新,尽管控制台显示todosState.todos的数据已经完成更新。
相关代码实现
todoLists.js中的todoListsState与markAsActive()
import todos from '@/modules/todos.js' // ... some code ... const todoListsState = reactive({ todoLists: [], todoListsAreLoading: false, removedTodoListId: null, editedTodoListId: null, editedTodoListName: '', baseTodoListsApiUrl: process.env.VUE_APP_BASE_TODO_LISTS_API_URL, todoListCreationFormModalId: 'todoListCreationFormModal', todoListNameChangeFormModalId: 'todoListNameChangeFormModal' }); // ... some code ... function markAsActive(value) { let { close } = infoToast(); if (value) { axios.post((todoListsState.baseTodoListsApiUrl + 'mark-as-active'), { activatedTodoListId: value }).then(function () { getTodoLists(); const { getTodos } = todos(); getTodos(); }).catch(function () { dangerToast('Failed to mark to-do list as active.'); }).finally(() => { close(); }); } }
todos.js中的todosState与getTodos()
const todosState = reactive({ todos: [], activeTodoListId: 0, removedTodoId: null, editedTodoId: null, editedTodoText: '', todosAreLoading: false, baseTodosApiUrl: process.env.VUE_APP_BASE_TODOS_API_URL, todoAdditionFormModalId: 'todoAdditionFormModal', todoEditFormModalId: 'todoEditFormModal' }); // ... some code ... async function getTodos() { try { todosState.todosAreLoading = true; const response = await axios.get(todosState.baseTodosApiUrl); todosState.activeTodoListId = response.data[0]; todosState.todos = response.data[1]; } catch (e) { dangerToast('To-dos loading failed.'); } finally { todosState.todosAreLoading = false; } }
排查发现
控制台打印的todosState.todos数据已成功更新,且确认数组未丢失响应式特性,但TodoList组件始终未触发重新渲染。
问题原因
核心问题在于todos.js的导出方式:如果todos.js是通过工厂函数(调用函数返回状态和方法)的形式导出,那么每次调用todos()都会创建一个全新的reactive状态实例。
TodoList组件引用的是某一次调用todos()生成的状态实例markAsActive中调用todos()得到的是另一个全新实例,调用getTodos()更新的是这个新实例的状态,和组件引用的不是同一个对象,自然无法触发组件更新。
解决方法
将todos.js改为单例模式,确保全局只存在一个状态实例:
修改todos.js的导出方式
import { reactive } from 'vue'; import axios from 'axios'; // 导入你的toast方法... const todosState = reactive({ todos: [], activeTodoListId: 0, removedTodoId: null, editedTodoId: null, editedTodoText: '', todosAreLoading: false, baseTodosApiUrl: process.env.VUE_APP_BASE_TODOS_API_URL, todoAdditionFormModalId: 'todoAdditionFormModal', todoEditFormModalId: 'todoEditFormModal' }); async function getTodos() { try { todosState.todosAreLoading = true; const response = await axios.get(todosState.baseTodosApiUrl); todosState.activeTodoListId = response.data[0]; todosState.todos = response.data[1]; } catch (e) { dangerToast('To-dos loading failed.'); } finally { todosState.todosAreLoading = false; } } // 直接导出单例的状态和方法,而非工厂函数 export default { todosState, getTodos };
修改todoLists.js中的调用方式
// 导入单例,不再调用函数 import todos from '@/modules/todos.js' // ... some code ... function markAsActive(value) { let { close } = infoToast(); if (value) { axios.post((todoListsState.baseTodoListsApiUrl + 'mark-as-active'), { activatedTodoListId: value }).then(function () { getTodoLists(); // 直接调用单例上的getTodos todos.getTodos(); }).catch(function () { dangerToast('Failed to mark to-do list as active.'); }).finally(() => { close(); }); } }
这样一来,TodoList组件和markAsActive函数操作的是同一个todosState实例,当getTodos更新状态后,组件会正常响应并重新渲染。
内容的提问来源于stack exchange,提问作者user18630923
相关产品推荐
相关产品推荐

