Add a mutation queue to fix race conditions in toggles (#1933)

* Prototype a queue

* Track both current and pending actions

* Skip unnecessary actions

* Commit last confirmed state to shadow

* Thread state through actions over time

* Fix the logic to skip redundant mutations

* Track status

* Extract an abstraction

* Fix standalone mutations

* Add types

* Move to another file

* Return stable function

* Clean up

* Use queue for muting

* Use queue for blocking

* Convert other follow buttons

* Don't export non-queue mutations

* Properly handle canceled tasks

* Fix copy paste
This commit is contained in:
dan
2023-11-16 22:01:01 +00:00
committed by GitHub
parent 54faa7e176
commit 8475312422
6 changed files with 453 additions and 188 deletions
+10 -21
View File
@@ -3,10 +3,7 @@ import {StyleProp, TextStyle, View} from 'react-native'
import {AppBskyActorDefs} from '@atproto/api'
import {Button, ButtonType} from '../util/forms/Button'
import * as Toast from '../util/Toast'
import {
useProfileFollowMutation,
useProfileUnfollowMutation,
} from '#/state/queries/profile'
import {useProfileFollowMutationQueue} from '#/state/queries/profile'
import {Shadow} from '#/state/cache/types'
export function FollowButton({
@@ -20,31 +17,25 @@ export function FollowButton({
profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
labelStyle?: StyleProp<TextStyle>
}) {
const followMutation = useProfileFollowMutation()
const unfollowMutation = useProfileUnfollowMutation()
const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile)
const onPressFollow = async () => {
if (profile.viewer?.following) {
return
}
try {
await followMutation.mutateAsync({did: profile.did})
await queueFollow()
} catch (e: any) {
Toast.show(`An issue occurred, please try again.`)
if (e?.name !== 'AbortError') {
Toast.show(`An issue occurred, please try again.`)
}
}
}
const onPressUnfollow = async () => {
if (!profile.viewer?.following) {
return
}
try {
await unfollowMutation.mutateAsync({
did: profile.did,
followUri: profile.viewer?.following,
})
await queueUnfollow()
} catch (e: any) {
Toast.show(`An issue occurred, please try again.`)
if (e?.name !== 'AbortError') {
Toast.show(`An issue occurred, please try again.`)
}
}
}
@@ -59,7 +50,6 @@ export function FollowButton({
labelStyle={labelStyle}
onPress={onPressUnfollow}
label="Unfollow"
withLoading={true}
/>
)
} else {
@@ -69,7 +59,6 @@ export function FollowButton({
labelStyle={labelStyle}
onPress={onPressFollow}
label="Follow"
withLoading={true}
/>
)
}