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:
parent
54faa7e176
commit
8475312422
6 changed files with 453 additions and 188 deletions
|
@ -13,10 +13,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
|||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {Trans} from '@lingui/macro'
|
||||
import {Shadow, useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {
|
||||
useProfileFollowMutation,
|
||||
useProfileUnfollowMutation,
|
||||
} from '#/state/queries/profile'
|
||||
import {useProfileFollowMutationQueue} from '#/state/queries/profile'
|
||||
import {logger} from '#/logger'
|
||||
|
||||
type Props = {
|
||||
|
@ -77,35 +74,32 @@ export function ProfileCard({
|
|||
const pal = usePalette('default')
|
||||
const [addingMoreSuggestions, setAddingMoreSuggestions] =
|
||||
React.useState(false)
|
||||
const {mutateAsync: follow} = useProfileFollowMutation()
|
||||
const {mutateAsync: unfollow} = useProfileUnfollowMutation()
|
||||
const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile)
|
||||
|
||||
const onToggleFollow = React.useCallback(async () => {
|
||||
try {
|
||||
if (
|
||||
profile.viewer?.following &&
|
||||
profile.viewer?.following !== 'pending'
|
||||
) {
|
||||
await unfollow({did: profile.did, followUri: profile.viewer.following})
|
||||
} else if (
|
||||
!profile.viewer?.following &&
|
||||
profile.viewer?.following !== 'pending'
|
||||
) {
|
||||
if (profile.viewer?.following) {
|
||||
await queueUnfollow()
|
||||
} else {
|
||||
setAddingMoreSuggestions(true)
|
||||
await follow({did: profile.did})
|
||||
await queueFollow()
|
||||
await onFollowStateChange({did: profile.did, following: true})
|
||||
setAddingMoreSuggestions(false)
|
||||
track('Onboarding:SuggestedFollowFollowed')
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('RecommendedFollows: failed to toggle following', {error: e})
|
||||
} catch (e: any) {
|
||||
if (e?.name !== 'AbortError') {
|
||||
logger.error('RecommendedFollows: failed to toggle following', {
|
||||
error: e,
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
setAddingMoreSuggestions(false)
|
||||
}
|
||||
}, [
|
||||
profile,
|
||||
follow,
|
||||
unfollow,
|
||||
queueFollow,
|
||||
queueUnfollow,
|
||||
setAddingMoreSuggestions,
|
||||
track,
|
||||
onFollowStateChange,
|
||||
|
@ -142,7 +136,6 @@ export function ProfileCard({
|
|||
labelStyle={styles.followButton}
|
||||
onPress={onToggleFollow}
|
||||
label={profile.viewer?.following ? 'Unfollow' : 'Follow'}
|
||||
withLoading={true}
|
||||
/>
|
||||
</View>
|
||||
{profile.description ? (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue