fix: ensure async API calls are awaited in VideoSocialButton

- Make callback handlers async and await the API calls
- Add localLoading state to prevent duplicate clicks
- Add ActivityIndicator during loading
- Fix issue where API might not be called properly
This commit is contained in:
imeepos 2026-01-28 20:16:57 +08:00
parent 0d83020926
commit e699e5cada
1 changed files with 51 additions and 28 deletions

View File

@ -1,5 +1,5 @@
import React, { memo, useCallback } from 'react' import React, { memo, useCallback, useState } from 'react'
import { View, StyleSheet, Text, Pressable } from 'react-native' import { View, StyleSheet, Text, Pressable, ActivityIndicator } from 'react-native'
import { Ionicons } from '@expo/vector-icons' import { Ionicons } from '@expo/vector-icons'
export interface VideoSocialButtonProps { export interface VideoSocialButtonProps {
@ -9,10 +9,10 @@ export interface VideoSocialButtonProps {
likeCount?: number likeCount?: number
favoriteCount?: number favoriteCount?: number
loading?: boolean loading?: boolean
onLike?: () => void onLike?: () => Promise<void> | void
onUnlike?: () => void onUnlike?: () => Promise<void> | void
onFavorite?: () => void onFavorite?: () => Promise<void> | void
onUnfavorite?: () => void onUnfavorite?: () => Promise<void> | void
testID?: string testID?: string
} }
@ -29,27 +29,40 @@ const VideoSocialButtonComponent: React.FC<VideoSocialButtonProps> = ({
onUnfavorite, onUnfavorite,
testID, testID,
}) => { }) => {
// 本地 loading 状态,防止重复点击
const [localLoading, setLocalLoading] = useState(false)
// 处理点赞按钮点击 // 处理点赞按钮点击
const handleLikePress = useCallback(() => { const handleLikePress = useCallback(async () => {
if (!loading) { if (loading || localLoading) return
setLocalLoading(true)
try {
if (liked) { if (liked) {
onUnlike?.() await onUnlike?.()
} else { } else {
onLike?.() await onLike?.()
} }
} finally {
setLocalLoading(false)
} }
}, [loading, liked, onLike, onUnlike]) }, [loading, localLoading, liked, onLike, onUnlike])
// 处理收藏按钮点击 // 处理收藏按钮点击
const handleFavoritePress = useCallback(() => { const handleFavoritePress = useCallback(async () => {
if (!loading) { if (loading || localLoading) return
setLocalLoading(true)
try {
if (favorited) { if (favorited) {
onUnfavorite?.() await onUnfavorite?.()
} else { } else {
onFavorite?.() await onFavorite?.()
} }
} finally {
setLocalLoading(false)
} }
}, [loading, favorited, onFavorite, onUnfavorite]) }, [loading, localLoading, favorited, onFavorite, onUnfavorite])
// 格式化数量显示 // 格式化数量显示
const formatCount = (count?: number): string => { const formatCount = (count?: number): string => {
@ -63,21 +76,27 @@ const VideoSocialButtonComponent: React.FC<VideoSocialButtonProps> = ({
return count.toString() return count.toString()
} }
const isLoading = loading || localLoading
return ( return (
<View style={styles.container} testID={testID}> <View style={styles.container} testID={testID}>
{/* 点赞按钮 */} {/* 点赞按钮 */}
<Pressable <Pressable
style={styles.buttonWrapper} style={styles.buttonWrapper}
onPress={handleLikePress} onPress={handleLikePress}
disabled={loading} disabled={isLoading}
testID={testID ? `${testID}-like-button` : undefined} testID={testID ? `${testID}-like-button` : undefined}
> >
<View style={[styles.iconContainer, liked && styles.iconContainerActive]}> <View style={[styles.iconContainer, liked && styles.iconContainerActive]}>
<Ionicons {isLoading && liked ? (
name={liked ? 'heart' : 'heart-outline'} <ActivityIndicator size="small" color="#FF3B30" />
size={28} ) : (
color={liked ? '#FF3B30' : '#FFFFFF'} <Ionicons
/> name={liked ? 'heart' : 'heart-outline'}
size={28}
color={liked ? '#FF3B30' : '#FFFFFF'}
/>
)}
</View> </View>
<Text style={styles.count}>{formatCount(likeCount)}</Text> <Text style={styles.count}>{formatCount(likeCount)}</Text>
</Pressable> </Pressable>
@ -86,15 +105,19 @@ const VideoSocialButtonComponent: React.FC<VideoSocialButtonProps> = ({
<Pressable <Pressable
style={styles.buttonWrapper} style={styles.buttonWrapper}
onPress={handleFavoritePress} onPress={handleFavoritePress}
disabled={loading} disabled={isLoading}
testID={testID ? `${testID}-favorite-button` : undefined} testID={testID ? `${testID}-favorite-button` : undefined}
> >
<View style={[styles.iconContainer, favorited && styles.iconContainerActive]}> <View style={[styles.iconContainer, favorited && styles.iconContainerActive]}>
<Ionicons {isLoading && favorited ? (
name={favorited ? 'star' : 'star-outline'} <ActivityIndicator size="small" color="#FFD700" />
size={28} ) : (
color={favorited ? '#FFD700' : '#FFFFFF'} <Ionicons
/> name={favorited ? 'star' : 'star-outline'}
size={28}
color={favorited ? '#FFD700' : '#FFFFFF'}
/>
)}
</View> </View>
<Text style={styles.count}>{formatCount(favoriteCount)}</Text> <Text style={styles.count}>{formatCount(favoriteCount)}</Text>
</Pressable> </Pressable>