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




