Debounce thread preferences on leading edge, reduce to 2s (#9851)

* debounce on leading edge, reduce to 2s

* flush debounce on leave screen

* simplify by using useMutation properly
This commit is contained in:
Samuel Newman
2026-02-11 07:41:04 +00:00
committed by GitHub
parent 177a6e50bd
commit a25bc8f249
2 changed files with 39 additions and 19 deletions
+9 -1
View File
@@ -200,7 +200,13 @@ export function useSetFeedViewPreferencesMutation() {
}) })
} }
export function useSetThreadViewPreferencesMutation() { export function useSetThreadViewPreferencesMutation({
onSuccess,
onError,
}: {
onSuccess?: (data: void, variables: Partial<ThreadViewPreferences>) => void
onError?: (error: unknown) => void
}) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const agent = useAgent()
@@ -212,6 +218,8 @@ export function useSetThreadViewPreferencesMutation() {
queryKey: preferencesQueryKey, queryKey: preferencesQueryKey,
}) })
}, },
onSuccess,
onError,
}) })
} }
@@ -1,5 +1,6 @@
import {useCallback, useMemo, useRef, useState} from 'react' import {useCallback, useMemo, useRef, useState} from 'react'
import {type AppBskyUnspeccedGetPostThreadV2} from '@atproto/api' import {type AppBskyUnspeccedGetPostThreadV2} from '@atproto/api'
import {useFocusEffect} from '@react-navigation/native'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import {useCallOnce} from '#/lib/once' import {useCallOnce} from '#/lib/once'
@@ -70,26 +71,37 @@ export function useThreadPreferences({
} }
const userUpdatedPrefs = useRef(false) const userUpdatedPrefs = useRef(false)
const [isSaving, setIsSaving] = useState(false) const {mutate, isPending: isSaving} = useSetThreadViewPreferencesMutation({
const {mutateAsync} = useSetThreadViewPreferencesMutation() onSuccess: (_data, prefs) => {
const savePrefs = useMemo(() => {
return debounce(async (prefs: ThreadViewPreferences) => {
try {
setIsSaving(true)
await mutateAsync(prefs)
ax.metric('thread:preferences:update', { ax.metric('thread:preferences:update', {
sort: prefs.sort, sort: prefs.sort,
view: prefs.lab_treeViewEnabled ? 'tree' : 'linear', view: prefs.lab_treeViewEnabled ? 'tree' : 'linear',
}) })
} catch (e) { },
onError: err => {
ax.logger.error('useThreadPreferences failed to save', { ax.logger.error('useThreadPreferences failed to save', {
safeMessage: e, safeMessage: err,
}) })
} finally { },
setIsSaving(false) })
const savePrefs = useMemo(() => {
return debounce(
(prefs: ThreadViewPreferences) => {
mutate(prefs)
},
2e3,
{leading: true, trailing: true},
)
}, [mutate])
// flush on leave screen
useFocusEffect(
useCallback(() => {
return () => {
void savePrefs.flush()
} }
}, 4e3) }, [savePrefs]),
}, [mutateAsync]) )
if (save && userUpdatedPrefs.current) { if (save && userUpdatedPrefs.current) {
savePrefs({ savePrefs({