问题
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?
回答1:
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
来源:https://stackoverflow.com/questions/49118378/apollo-mutate-calling-update-four-times-for-a-single-mutation