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:
parent
0d83020926
commit
e699e5cada
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue