expo-popcore-app/components/blocks/ui/FavoriteButton.tsx

78 lines
1.7 KiB
TypeScript

import React, { memo, useCallback, useMemo } from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'
import { Ionicons } from '@expo/vector-icons'
export interface FavoriteButtonProps {
favorited?: boolean
loading?: boolean
count?: number
size?: number
onPress?: () => void
testID?: string
}
const FavoriteButtonComponent: React.FC<FavoriteButtonProps> = ({
favorited = false,
loading = false,
count,
size = 24,
onPress,
testID,
}) => {
// 使用 useCallback 缓存 onPress 回调
const handlePress = useCallback(() => {
if (!loading && onPress) {
onPress()
}
}, [loading, onPress])
// 缓存样式计算 - 移除不必要的 iconStyle
const containerStyle = useMemo(
() => [styles.container, loading && styles.disabled],
[loading]
)
// 根据收藏状态选择图标名称和颜色
const iconName = favorited ? 'star' : 'star-outline'
const iconColor = favorited ? '#FFD700' : '#8E8E93'
return (
<Pressable
onPress={handlePress}
disabled={loading}
testID={testID}
style={containerStyle}
>
<View style={styles.content}>
<Ionicons name={iconName} size={size} color={iconColor} />
{count !== undefined && (
<Text style={[styles.count, { fontSize: size * 0.7 }]}>{count}</Text>
)}
</View>
</Pressable>
)
}
export const FavoriteButton = memo(FavoriteButtonComponent)
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
padding: 8,
},
disabled: {
opacity: 0.5,
},
content: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
},
count: {
color: '#8E8E93',
fontWeight: '600',
marginLeft: 4,
},
})