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