You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

112 lines
3.1 KiB

/**
* 游戏分类菜单组件
*
* 展示游戏分类,支持切换,使用真实数据
*/
import React, { useRef, useEffect, useState, useCallback, useMemo } from 'react';
import { View, Text, ScrollView, TouchableOpacity, Animated } from 'react-native';
// import type { GameCategory } from '@/types/home';
import { styles } from './styles';
import { useGameMainMenus, useMenuDataLoaded } from '@/hooks/useGameMenus';
// import useGameStore from '@/stores/gameStore';
import { ThemeEnum } from '@/constants/theme';
interface GameMainMenuProps {
theme: ThemeEnum;
selectedCategory?: string;
onCategorySelect?: (categoryId: string) => void;
topHeight?: number;
showSubMenus?: boolean;
}
/**
* 游戏分类菜单组件
*/
export default function GameMainMenu({
theme,
selectedCategory = '103',
onCategorySelect,
topHeight = 0,
showSubMenus = true,
}: GameMainMenuProps) {
const s = styles[theme];
const scrollViewRef = useRef<ScrollView>(null);
const gameMenus = useGameMainMenus(theme);
// 检查数据加载完成
const isDataLoaded = useMenuDataLoaded();
// 使用 useMemo 缓存找到的索引,避免每次都重新计算
const selectedIndex = useMemo(() => {
return gameMenus.findIndex((cat) => cat.key === selectedCategory);
}, [selectedCategory, gameMenus]);
// 当分类改变时,滚动到该分类
useEffect(() => {
if (selectedIndex >= 0) {
scrollViewRef.current?.scrollTo({
x: selectedIndex * 100,
animated: true,
});
}
}, [selectedIndex]);
// 使用 useCallback 稳定 onPress 回调
const handleCategoryPress = useCallback((categoryKey: string) => {
onCategorySelect?.(categoryKey);
}, [onCategorySelect]);
// 骨架屏 - 显示加载中的占位符
const renderSkeleton = () => (
<View style={s.container}>
<ScrollView
style={s.scrollView}
horizontal
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
>
{[1, 2, 3, 4, 5].map((index) => (
<View
key={`skeleton-${index}`}
style={[s.categoryItem, { backgroundColor: theme === 'dark' ? '#333' : '#e0e0e0' }]}
/>
))}
</ScrollView>
</View>
);
// 如果动态数据还未加载,显示骨架屏
if (!isDataLoaded) {
return renderSkeleton();
}
return (
<View style={s.container}>
<ScrollView
ref={scrollViewRef}
style={s.scrollView}
horizontal
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
>
{gameMenus.map((menu) => (
<TouchableOpacity
key={menu.key}
style={[s.menuItem, selectedCategory === menu.key && s.menuItemActive]}
onPress={() => handleCategoryPress(menu.key)}
activeOpacity={0.7}
>
<Text
style={[s.menuText, selectedCategory === menu.key && s.menuTextActive]}
>
{menu.icon || '🎮'} {menu.name}
</Text>
</TouchableOpacity>
))}
</ScrollView>
</View>
);
}