From a2adec2b06d0565371fec0e8ae7ca4fc2003dff7 Mon Sep 17 00:00:00 2001 From: dongmucat <1127093059@qq.com> Date: Wed, 29 Apr 2026 14:47:17 +0800 Subject: [PATCH] fix(subscription): improve button spacing and eliminate toggle flicker - Add visual separator between StarButton and SubscribeButton - Use optimistic updates in useToggleSubscription for instant feedback - Remove isLoading guard that caused button to unmount during refetch --- web/src/features/social/subscribe-button.tsx | 4 ++-- web/src/features/social/use-subscription.ts | 16 +++++++++++++++- web/src/pages/skill-detail.tsx | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/web/src/features/social/subscribe-button.tsx b/web/src/features/social/subscribe-button.tsx index 9c655dcc..bbe96976 100644 --- a/web/src/features/social/subscribe-button.tsx +++ b/web/src/features/social/subscribe-button.tsx @@ -12,7 +12,7 @@ interface SubscribeButtonProps { export function SubscribeButton({ skillId, subscriptionCount, onRequireLogin }: SubscribeButtonProps) { const { t } = useTranslation() - const { data: subscriptionStatus, isLoading } = useSubscription(skillId) + const { data: subscriptionStatus } = useSubscription(skillId) const toggleMutation = useToggleSubscription(skillId) const { isAuthenticated } = useAuth() @@ -26,7 +26,7 @@ export function SubscribeButton({ skillId, subscriptionCount, onRequireLogin }: } } - if (isLoading || !subscriptionStatus) { + if (!subscriptionStatus) { return null } diff --git a/web/src/features/social/use-subscription.ts b/web/src/features/social/use-subscription.ts index 8d91b563..9a6b3637 100644 --- a/web/src/features/social/use-subscription.ts +++ b/web/src/features/social/use-subscription.ts @@ -44,7 +44,21 @@ export function useToggleSubscription(skillId: number) { return useMutation({ mutationFn: (subscribed: boolean) => toggleSubscription(skillId, subscribed), - onSuccess: () => { + onMutate: async (currentSubscribed: boolean) => { + await queryClient.cancelQueries({ queryKey: ['skills', skillId, 'subscription'] }) + const previous = queryClient.getQueryData(['skills', skillId, 'subscription']) + queryClient.setQueryData( + ['skills', skillId, 'subscription'], + { subscribed: !currentSubscribed }, + ) + return { previous } + }, + onError: (_error, _variables, context) => { + if (context?.previous !== undefined) { + queryClient.setQueryData(['skills', skillId, 'subscription'], context.previous) + } + }, + onSettled: () => { queryClient.invalidateQueries({ queryKey: ['skills', skillId, 'subscription'] }) queryClient.invalidateQueries({ queryKey: ['skills'] }) queryClient.invalidateQueries({ queryKey: ['skills', 'subscriptions'] }) diff --git a/web/src/pages/skill-detail.tsx b/web/src/pages/skill-detail.tsx index 7439241e..14ecee44 100644 --- a/web/src/pages/skill-detail.tsx +++ b/web/src/pages/skill-detail.tsx @@ -1070,6 +1070,7 @@ export function SkillDetailPage() { {!isFetchingSkill ? ( <> +