You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vuedraggable结合Apollo Mutation实现看板时出现重复显示问题求助

问题分析与解决方案

问题根源

你遇到的卡片重复显示问题,核心原因是Apollo缓存与本地组件数据的同步不一致:

  1. 拖拽时Vuedraggable已经修改了组件本地的stage.ticketIds列表,但Apollo缓存中的Stage数据仍保留旧状态;
  2. Mutation执行完成后,Apollo默认只会更新缓存中单个Ticket的信息,不会自动更新关联Stage下的ticketIds数组——导致旧Stage的缓存数据还包含被移动的Ticket,而本地组件的新Stage已经添加了该Ticket,两者叠加就出现了重复显示;
  3. 你的update函数仅打印缓存,没有手动修正缓存中的Stage数组,进一步加剧了数据不一致;
  4. 原本的Mutation返回缺少Ticket的name字段,和查询时的结构不匹配,可能导致缓存更新后数据缺失。

解决方法

方法一:手动更新Apollo缓存(推荐,无额外网络请求)

这种方式直接在本地修改缓存,效率更高,是Apollo最佳实践之一。

  1. 完善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 } 
  }
}
`
  1. 修改拖拽事件处理函数,实现缓存同步逻辑
    在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 09:32:44