Vue3项目中Axios请求requestBody与实际传入数据不同步问题
问题触发原因
- 事件触发时序错误:ion-toggle的
@click事件触发时机早于v-model绑定值的更新时机,回调执行时emit的仍是更新前的数据。控制台打印引用类型对象显示值正确,是因为浏览器控制台默认存储对象引用,展开时才读取最新值,并非打印时刻数据已经完成更新。 - 违反单向数据流规则:子组件直接通过
v-model修改Props传入的数组内部属性,Props为父组件传递的只读数据,直接修改会导致状态更新脱离Vue响应式调度规则,出现时序异常。 - 非法修改Vuex状态:传入的
searchFiltersArr来自Vuex state,Vuex要求所有状态修改必须通过commit mutation完成,直接在子组件修改state属性会导致状态更新无追踪、异步不同步。 - 硬编码setTimeout生效的原因:setTimeout属于宏任务,会等待当前事件循环的所有微任务(含Vue的批量状态更新、v-model赋值)执行完毕后再执行,因此能拿到更新后的状态。
解决方案
- 替换监听事件:将ion-toggle的
@click替换为Ionic组件官方推荐的@ionChange事件,确保回调触发时toggle的选中值已经完成更新。 - 遵守单向数据流规则:子组件不直接修改Props值,仅向父组件emit当前变更的filter标识和最新选中状态,由父组件完成状态更新。
- 合法修改Vuex状态:父组件收到子组件的变更事件后,先提交mutation更新Vuex状态,再构造请求参数。
- 确保状态更新完成后再发起请求:使用
await nextTick()等待本次响应式更新全部完成,替代硬编码的setTimeout,性能更稳定。 - 构造请求参数时做深拷贝:对引用类型的请求参数做深拷贝生成快照,避免后续状态更新影响已构造的请求体。
代码修改示例
子组件(filters.vue)
<template> <ion-toggle @ionChange="changedFilter" :checked="filter.selected" slot="end" > </ion-toggle> </template> <script> export default { props: ['searchFiltersArr'], emits: ['changedFilter'], setup(props, { emit }) { const changedFilter = (e) => { // 替换为你的filter唯一标识字段 const filterId = filter.id const newSelected = e.detail.checked emit("changedFilter", filterId, newSelected); }; return { changedFilter, filters: props.searchFiltersArr, }; } } </script>
父组件(SearchFilters.vue)
<template> <filters @changed-filter="updateFilter" :searchFiltersArr="searchParameters" ></filters> </template> <script> import { defineComponent, computed, nextTick } from 'vue' import { useStore } from 'vuex' export default defineComponent({ name: "SearchFilters", components: { Filters }, setup() { const store = useStore(); const searchParameters = computed(() => store.state.user.settings.searchParameters); async function updateFilter(filterId, newSelected) { // 先提交mutation更新Vuex状态 store.commit('updateSearchFilter', { id: filterId, selected: newSelected }) // 等待状态更新完成 await nextTick() const headers = { "Content-type": "application/json", Authorization: "Bearer 21345", }; // 深拷贝参数生成快照 const requestBody = { user: { name: "", email: "email@email.com", }, searchParameters: JSON.parse(JSON.stringify(searchParameters.value)) }; await apiClient.put("/settings", requestBody, { headers }); } return { updateFilter, searchParameters, }; }, }); </script>
内容的提问来源于stack exchange,提问作者Anfield_08
相关产品推荐
相关产品推荐

