Apollo mutate 为单个突变调用更新四次 [英] Apollo mutate calling update four times for a single mutation

查看:42
本文介绍了Apollo mutate 为单个突变调用更新四次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每次我在我的应用程序中添加一个新项目时,由于某种原因,mutation 会调用 update() 四次 次.前两个是乐观数据,第二批一个是乐观数据,一个是来自网络的真实数据.我无法理解这一点.正在创建的新项目在页面上出现两次.

这是我的突变:

mutation CreateTrack($name: String!, $trackNum: Int, $s3Key: String!) {createTrack(name: $name, trackNum: $trackNum, s3Key: $s3Key) {轨道标识姓名创建于期间轨道编号s3key正在处理处理失败}}

这是突变代码:

createTrack({ name, s3Key }) {const newTrack = {姓名,s3Key,};这个.$apollo.mutate({突变:createTrackMutation,变量:newTrack,更新:(商店,{数据:{createTrack}})=>{console.log('这太蠢了', JSON.stringify(createTrack, null, 2));常量变量 = {限制:this.pageSize,顺序: this.order === '升序' ?'升序':'降序',sortBy: this.sortBy,};const 数据 = store.readQuery({查询:listTracksQuery,变量,});data.listTracks.items.push(createTrack);store.writeQuery({查询:listTracksQuery,变量,数据,});},乐观响应:{__typename: '突变',创建跟踪:{__typename: '跟踪',...新轨道,trackId: '??',createdAt: 新日期().toISOString(),isProcessing: 真,didProcessingFail: 假,持续时间:空,曲目编号:999,},},}).then(数据=> {console.log('done!', data);}).catch(错误 => {console.log('错误', 错误);});},

最后,这里是调用 mutate 一次的控制台日志:

这很愚蠢{"__typename": "跟踪","name": "small2.wav","s3Key": "舞台/音频/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav","trackId": "??","createdAt": "2018-03-05T03:30:18.246Z",isProcessing":真,didProcessingFail":假,持续时间":空,trackNum":999}这是愚蠢的{"__typename": "跟踪","name": "small2.wav","s3Key": "舞台/音频/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav","trackId": "??","createdAt": "2018-03-05T03:30:18.246Z",isProcessing":真,didProcessingFail":假,持续时间":空,trackNum":999}完毕!{数据: {...}}这是愚蠢的{"__typename": "跟踪","name": "small2.wav","s3Key": "舞台/音频/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav","trackId": "??","createdAt": "2018-03-05T03:30:18.246Z",isProcessing":真,didProcessingFail":假,持续时间":空,trackNum":999}这是愚蠢的{"trackId": "2b3de8ac-d145-4da6-b522-27e5413d43e1","name": "small2.wav","createdAt": "2018-03-05T03:30:18.627Z",持续时间":空,"trackNum": 999,"s3Key": "舞台/音频/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav",isProcessing":真,didProcessingFail":空,"__typename": "跟踪"}

我在这里做错了什么?

解决方案

我刚刚与负责此代码的工程师聊了聊.您看到的是 AWS AppSync 开发工具包流程在幕后使用的簿记流程,以确保数据完整性.它并非实际上针对您的 API 运行了 4 次变异.

当 AppSync 客户端获得乐观响应时,更新功能会运行两次 - 一次用于本地响应,一次用于网络响应.这是标准的 Apollo 行为.AppSync 客户端在幕后所做的是第一个乐观响应,我们将其视为网络响应并将数据存储在持久存储介质中(Web 本地存储,React Native 异步存储)以允许乐观 UI处于离线状态时.这本质上是一个发件箱",数据在离线时首先写入(当前实现使用 Redux Offline),如果您使用 disableOffline:true 禁用离线,您将不再看到这种行为.>

当您重新上线时,同步过程将被执行,您会看到客户端向服务器发送的另一个突变消息(实际上是原始突变)和相应的响应.

请注意,如果您在客户端的乐观响应中创建唯一 ID 并且还在服务器上创建唯一 ID,例如使用 $util.autoId() 那么您可能会有重复的记录因为我们不会覆盖您明确分配了 ID 的任何本地数据.如果您愿意,您可以使用 AppSync 的 DynamoDB 解析器中的支持离线的放置项支持离线的响应模板来使任何本地创建的 ID 失效,这些模板使用名为 relayState 的临时键(您需要将其添加为您正在创建的类型的字段),您可以使用它来跟踪本地 ID 并将其与创建的 ID 匹配服务器.

我们将在未来对该簿记过程进行更多补充,欢迎在我们的 GitHub 问题存储库中提出建议:https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues

Every time I add a new item in my app, the mutation calls update() four times, for some reason. The first two are optimistic data, and in the second batch, one is optimistic and one is real data from the network. I can't make any sense of this. The new item being created shows up twice on the page.

This is my mutation:

mutation CreateTrack($name: String!, $trackNum: Int, $s3Key: String!) {
  createTrack(name: $name, trackNum: $trackNum, s3Key: $s3Key) {
    trackId
    name
    createdAt
    duration
    trackNum
    s3Key
    isProcessing
    didProcessingFail
  }
}

And this is the mutation code:

createTrack({ name, s3Key }) {
  const newTrack = {
    name,
    s3Key,
  };

  this.$apollo
    .mutate({
      mutation: createTrackMutation,
      variables: newTrack,
      update: (store, { data: { createTrack } }) => {
        console.log('this is dumb', JSON.stringify(createTrack, null, 2));
        const variables = {
          limit: this.pageSize,
          order: this.order === 'ascending' ? 'asc' : 'desc',
          sortBy: this.sortBy,
        };
        const data = store.readQuery({
          query: listTracksQuery,
          variables,
        });
        data.listTracks.items.push(createTrack);
        store.writeQuery({
          query: listTracksQuery,
          variables,
          data,
        });
      },
      optimisticResponse: {
        __typename: 'Mutation',
        createTrack: {
          __typename: 'Track',
          ...newTrack,
          trackId: '??',
          createdAt: new Date().toISOString(),
          isProcessing: true,
          didProcessingFail: false,
          duration: null,
          trackNum: 999,
        },
      },
    })
    .then(data => {
      console.log('done!', data);
    })
    .catch(err => {
      console.log('error', err);
    });
},

And finally, here are the console logs for calling mutate once:

this is dumb {
  "__typename": "Track",
  "name": "small2.wav",
  "s3Key": "staging/audio/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav",
  "trackId": "??",
  "createdAt": "2018-03-05T03:30:18.246Z",
  "isProcessing": true,
  "didProcessingFail": false,
  "duration": null,
  "trackNum": 999
}

this is dumb {
  "__typename": "Track",
  "name": "small2.wav",
  "s3Key": "staging/audio/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav",
  "trackId": "??",
  "createdAt": "2018-03-05T03:30:18.246Z",
  "isProcessing": true,
  "didProcessingFail": false,
  "duration": null,
  "trackNum": 999
}

done! {data: {...}}

this is dumb {
  "__typename": "Track",
  "name": "small2.wav",
  "s3Key": "staging/audio/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav",
  "trackId": "??",
  "createdAt": "2018-03-05T03:30:18.246Z",
  "isProcessing": true,
  "didProcessingFail": false,
  "duration": null,
  "trackNum": 999
}

this is dumb {
  "trackId": "2b3de8ac-d145-4da6-b522-27e5413d43e1",
  "name": "small2.wav",
  "createdAt": "2018-03-05T03:30:18.627Z",
  "duration": null,
  "trackNum": 999,
  "s3Key": "staging/audio/10e3e675-e7a6-41dc-a8fb-686ad683e40e.wav",
  "isProcessing": true,
  "didProcessingFail": null,
  "__typename": "Track"
}

What am I doing wrong here?

解决方案

I just chatted through this with the Engineer that worked on this code. What you're seeing is the bookeeping process that the AWS AppSync SDK process uses under the covers to ensure data integrity. It is NOT actually running a mutation 4 times against your API.

When the AppSync client gets an optimistic response the update function runs twice - once for the local response and once for the network response. This is standard Apollo behavior. What the AppSync client does under the covers is on the first optimistic response, we treat it as if it were the network response and store the data in a persistent storage medium (local storage for web, Async Storage for React Native) to allow optimistic UI when in an offline state. This is essentially an "outbox" that the data first gets written to when offline (currently the implementation uses Redux Offline) and if you disable offline with disableOffline:true you will no longer see this behavior.

When you come back online, the synchronization process gets executed and you see another mutation message (which is actually the original mutation) of the client sending this to the server and the appropriate response.

Note that if you are creating unique IDs in your optimistic response on the client AND also creating unique IDs on the server, for instance using the $util.autoId() then you could have duplicate records as we will not overwrite any local data you've explicitly assigned an ID. You can do invalidation of any locally-created IDs if you wish by using the Offline-enabled put item and Offline-enabled response templates in the DynamoDB resolvers for AppSync which use an ephemeral key called relayState (that you'll need to add as a field for the type you're creating) that you can use to track the local ID and match it up with the ID that was created at the server.

There are more additions we're going to be making to this bookeeping process in the future and would welcome suggestions in our GitHub issues repo: https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues

这篇关于Apollo mutate 为单个突变调用更新四次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆