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

80 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 LikeButtonProps {
liked?: boolean
loading?: boolean
count?: number
size?: number
onPress?: () => void
testID?: string
}
const LikeButtonComponent: React.FC<LikeButtonProps> = ({
liked = false,
loading = false,
count,
size = 24,
onPress,
testID,
}) => {
// 使用 useCallback 缓存 onPress 回调
const handlePress = useCallback(() => {
if (!loading && onPress) {
onPress()
}
}, [loading, onPress])
// 缓存样式计算
const containerStyle = useMemo(() => [styles.container, loading && styles.disabled], [loading])
// 根据点赞状态选择图标名称和颜色
const iconName = liked ? 'heart' : 'heart-outline'
const iconColor = liked ? '#FF3B30' : '#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 LikeButton = memo(LikeButtonComponent)
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
padding: 8,
},
disabled: {
opacity: 0.5,
},
content: {
flexDirection: 'row',
alignItems: 'center',
},
count: {
color: '#8E8E93',
fontWeight: '600',
marginLeft: 4,
},
})