Vue中更新Proxy Array问题:点击加载更多事件列表
解决事件列表追加时的嵌套与重复问题
问题根源
- 每次调用
useSearchEventsForHomePage传入months=n时,接口返回的是从当前到n个月后的所有事件,包含之前已加载的月份内容,直接追加会导致重复数据。 - 使用
events.value.push(moreEvents.value)会把整个数组作为单个元素推入原数组,形成[[事件1,事件2], [事件1,事件2,事件3,事件4]]的嵌套结构,导致v-for渲染异常。 useFetch返回的data是Vue响应式Proxy对象,但核心问题是数组操作逻辑错误,和Proxy本身的工作原理关联不大。
修正方案
1. 调整接口请求逻辑,只请求新增月份的事件
修改useSearchEventsForHomePage,支持指定起始和结束的月份偏移,每次“查看更多”仅请求新增的一个月事件:
export function useSearchEventsForHomePage(startOffsetMonths: number = 0, endOffsetMonths: number = 1) { const config = useRuntimeConfig().public; const startDate = DateTime.local().plus({ minutes: 1, months: startOffsetMonths }).toUTC().toISO(); const endDate = DateTime.local().plus({ months: endOffsetMonths }).toUTC().toISO(); const url = `${config.eventApiUrl}/events/search?startDate=${encodeURIComponent(startDate)}&endDate=${encodeURIComponent(endDate)}&summariseDates=false`; const options = { method: 'GET', lazy: true, key: url, default: () => [], }; return useFetch<Event[]>(url, options); }
2. 修改页面逻辑,正确追加新增事件
const currentMaxMonths = ref(1); const events = ref<Event[]>([]); // 初始化加载第一个月事件 const initEvents = async () => { const { data: firstMonthEvents } = await useSearchEventsForHomePage(0, currentMaxMonths.value); events.value = firstMonthEvents.value || []; }; initEvents(); async function seeMore() { const prevMaxMonths = currentMaxMonths.value; currentMaxMonths.value++; // 请求新增的月份区间:从prevMaxMonths到currentMaxMonths const { data: moreEvents } = await useSearchEventsForHomePage(prevMaxMonths, currentMaxMonths.value); // 用扩展运算符逐个追加新事件,避免嵌套 if (moreEvents.value) { events.value.push(...moreEvents.value); } }
3. 若无法修改接口(只能请求累计月份)
如果接口仅支持返回累计n个月的事件,需过滤重复事件后再追加:
const searchPeriod = ref(1); const events = ref<Event[]>([]); // 初始化加载 const initEvents = async () => { const { data: firstMonthEvents } = await useSearchEventsForHomePage(searchPeriod.value); events.value = firstMonthEvents.value || []; }; initEvents(); async function seeMore() { searchPeriod.value++; const { data: moreEvents } = await useSearchEventsForHomePage(searchPeriod.value); if (!moreEvents.value) return; // 过滤原数组已存在的事件(假设事件有唯一id字段) const newEvents = moreEvents.value.filter(event => !events.value.some(e => e.id === event.id)); // 追加新事件 events.value.push(...newEvents); }
关键说明
- 用
push(...moreEvents.value)替代push(moreEvents.value),可将新数组的每个元素单独推入原数组,彻底避免嵌套问题。 - 优先选择“请求新增月份”的方案,减少数据传输量和重复处理,性能更优。
内容的提问来源于stack exchange,提问作者maisiemay06





