optimistic updates for liking custom feeds

zio/stable
Ansh Nanda 2023-05-22 16:35:37 -07:00
parent 762bd15ed6
commit 64e303d911
2 changed files with 40 additions and 12 deletions

View File

@ -4,6 +4,22 @@ import set from 'lodash.set'
const ongoingActions = new Set<any>()
/**
* This is a TypeScript function that optimistically updates data on the client-side before sending a
* request to the server and rolling back changes if the request fails.
* @param {T} model - The object or record that needs to be updated optimistically.
* @param preUpdate - `preUpdate` is a function that is called before the server update is executed. It
* can be used to perform any necessary actions or updates on the model or UI before the server update
* is initiated.
* @param serverUpdate - `serverUpdate` is a function that returns a Promise representing the server
* update operation. This function is called after the previous state of the model has been recorded
* and the `preUpdate` function has been executed. If the server update is successful, the `postUpdate`
* function is called with the result
* @param [postUpdate] - `postUpdate` is an optional callback function that will be called after the
* server update is successful. It takes in the response from the server update as its parameter. If
* this parameter is not provided, nothing will happen after the server update.
* @returns A Promise that resolves to `void`.
*/
export const updateDataOptimistically = async <
T extends Record<string, any>,
U,

View File

@ -2,6 +2,7 @@ import {AppBskyFeedDefs} from '@atproto/api'
import {makeAutoObservable, runInAction} from 'mobx'
import {RootStoreModel} from 'state/models/root-store'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {updateDataOptimistically} from 'lib/async/revertible'
export class CustomFeedModel {
// data
@ -58,12 +59,19 @@ export class CustomFeedModel {
async like() {
try {
const res = await this.rootStore.agent.like(this.data.uri, this.data.cid)
runInAction(() => {
this.data.viewer = this.data.viewer || {}
this.data.viewer.like = res.uri
this.data.likeCount = (this.data.likeCount || 0) + 1
})
await updateDataOptimistically(
this.data,
() => {
this.data.viewer = this.data.viewer || {}
this.data.viewer.like = 'pending'
this.data.likeCount = (this.data.likeCount || 0) + 1
},
() => this.rootStore.agent.like(this.data.uri, this.data.cid),
res => {
this.data.viewer = this.data.viewer || {}
this.data.viewer.like = res.uri
},
)
} catch (e: any) {
this.rootStore.log.error('Failed to like feed', e)
}
@ -74,12 +82,16 @@ export class CustomFeedModel {
return
}
try {
await this.rootStore.agent.deleteLike(this.data.viewer.like!)
runInAction(() => {
this.data.viewer = this.data.viewer || {}
this.data.viewer.like = undefined
this.data.likeCount = (this.data.likeCount || 1) - 1
})
const likeUri = this.data.viewer.like
await updateDataOptimistically(
this.data,
() => {
this.data.viewer = this.data.viewer || {}
this.data.viewer.like = undefined
this.data.likeCount = (this.data.likeCount || 1) - 1
},
() => this.rootStore.agent.deleteLike(likeUri),
)
} catch (e: any) {
this.rootStore.log.error('Failed to unlike feed', e)
}