Vuedraggable结合Apollo Mutation实现看板时出现重复显示问题求助
问题分析与解决方案
问题根源
你遇到的卡片重复显示问题,核心原因是Apollo缓存与本地组件数据的同步不一致:
- 拖拽时
Vuedraggable已经修改了组件本地的stage.ticketIds列表,但Apollo缓存中的Stage数据仍保留旧状态; - Mutation执行完成后,Apollo默认只会更新缓存中单个Ticket的信息,不会自动更新关联Stage下的
ticketIds数组——导致旧Stage的缓存数据还包含被移动的Ticket,而本地组件的新Stage已经添加了该Ticket,两者叠加就出现了重复显示; - 你的
update函数仅打印缓存,没有手动修正缓存中的Stage数组,进一步加剧了数据不一致; - 原本的Mutation返回缺少Ticket的
name字段,和查询时的结构不匹配,可能导致缓存更新后数据缺失。
解决方法
方法一:手动更新Apollo缓存(推荐,无额外网络请求)
这种方式直接在本地修改缓存,效率更高,是Apollo最佳实践之一。
- 完善Mutation返回字段
确保返回的Ticket数据和组件查询时的结构一致,补充name字段:
const CHANGE_HELPDESK_TICKET_STAGE_MUTATION = gql` mutation changeHelpdeskTicketStageMutation ( $ticketId: ID!, $stageId: ID! ) { changeHelpdeskTicketStage ( ticketId: $ticketId, stageId: $stageId ) { id, name, # 新增name字段,匹配查询的结构 isClosed, stageId { id name } } } `
- 修改拖拽事件处理函数,实现缓存同步逻辑
在changeTicketStage中,通过update函数手动修改缓存中的Stage数组:
changeTicketStage (event, newStage) { if (event.added) { // 从拖拽事件中获取旧Stage(绑定在旧容器的vm实例上) const oldStage = event.oldContainer.vm.stage; const movedTicket = event.added.element; this.$apollo.mutate({ mutation: CHANGE_HELPDESK_TICKET_STAGE_MUTATION, variables: { ticketId: movedTicket.id, stageId: newStage.id }, update: (cache, { data: { changeHelpdeskTicketStage } }) => { // 定义和组件中获取Stages一致的查询语句 const GET_STAGES_QUERY = gql` query GetHelpdeskTicketStages { helpdeskTicketStages { id name ticketIds { id name } } } `; // 读取缓存中的当前Stages数据 const { helpdeskTicketStages } = cache.readQuery({ query: GET_STAGES_QUERY }); // 更新Stages数组:移除旧Stage的Ticket,添加到新Stage const updatedStages = helpdeskTicketStages.map(stage => { // 处理旧Stage:移除被移动的Ticket if (stage.id === oldStage.id) { return { ...stage, ticketIds: stage.ticketIds.filter(ticket => ticket.id !== movedTicket.id) }; } // 处理新Stage:添加更新后的Ticket if (stage.id === newStage.id) { return { ...stage, ticketIds: [...stage.ticketIds, changeHelpdeskTicketStage] }; } // 其他Stage保持不变 return stage; }); // 将更新后的Stages写回缓存 cache.writeQuery({ query: GET_STAGES_QUERY, data: { helpdeskTicketStages: updatedStages } }); } }); } }
方法二:使用refetchQueries重新拉取数据(简单但有额外请求)
如果觉得手动更新缓存太繁琐,可以让Apollo在Mutation完成后重新查询所有Stages,自动覆盖缓存:
changeTicketStage (event, stage) { if (event.added) { this.$apollo.mutate({ mutation: CHANGE_HELPDESK_TICKET_STAGE_MUTATION, variables: { ticketId: event.added.element.id, stageId: stage.id }, // 重新拉取Stages数据,强制更新缓存 refetchQueries: [{ query: gql` query GetHelpdeskTicketStages { helpdeskTicketStages { id name ticketIds { id name } } } ` }] }) } }
注意:这种方式会触发额外的网络请求,适合数据量较小的场景。
额外注意事项
- 你当前的组件
key绑定是正确的(v-col用stage.id,v-card用ticket.id),避免了因key重复导致的渲染异常; - 后端
HelpdeskTicketType要确保name字段已暴露,否则Mutation返回的Ticket会缺少该字段,导致界面渲染异常。
内容的提问来源于stack exchange,提问作者lbris
相关产品推荐
相关产品推荐

