Browse Source

奖池标签切换卡顿优化

zbb 3 tháng trước cách đây
mục cha
commit
158ac697d1
1 tập tin đã thay đổi với 98 bổ sung40 xóa
  1. 98 40
      app/(tabs)/index.tsx

+ 98 - 40
app/(tabs)/index.tsx

@@ -1,19 +1,19 @@
 import { useRouter } from 'expo-router';
-import React, { useCallback, useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
 import {
-  ActivityIndicator,
-  ImageBackground,
-  RefreshControl,
-  ScrollView,
-  StatusBar,
-  StyleSheet,
-  Text,
-  View,
+    ActivityIndicator,
+    FlatList,
+    ImageBackground,
+    RefreshControl,
+    StatusBar,
+    StyleSheet,
+    Text,
+    View,
 } from 'react-native';
 import { useSafeAreaInsets } from 'react-native-safe-area-context';
 
 import { Banner } from '@/components/home/Banner';
-import { GoodsList } from '@/components/home/GoodsList';
+import { GoodsCard } from '@/components/home/GoodsCard';
 import { IPFilter } from '@/components/home/IPFilter';
 import { QuickEntry } from '@/components/home/QuickEntry';
 import { SearchBar } from '@/components/home/SearchBar';
@@ -29,6 +29,7 @@ export default function HomeScreen() {
   const router = useRouter();
   const [refreshing, setRefreshing] = useState(false);
   const [loading, setLoading] = useState(true);
+  const [listLoading, setListLoading] = useState(false);
 
   // 数据状态
   const [goods, setGoods] = useState<GoodsItem[]>([]);
@@ -48,6 +49,7 @@ export default function HomeScreen() {
   // 加载商品列表
   const loadGoods = useCallback(async (params: GoodsListParams, append = false) => {
     try {
+      if (!append) setListLoading(true);
       const data = await getGoodsList(params);
       if (append) {
         setGoods((prev) => [...prev, ...data]);
@@ -56,6 +58,8 @@ export default function HomeScreen() {
       }
     } catch (error) {
       console.error('加载商品失败:', error);
+    } finally {
+      if (!append) setListLoading(false);
     }
   }, []);
 
@@ -125,11 +129,17 @@ export default function HomeScreen() {
   };
 
   // IP 筛选
-  const handleIPSelect = async (item: IPItem, index: number) => {
+  const handleIPSelect = (item: IPItem, index: number) => {
+    // 立即更新 UI,不等待网络请求
     setIpIndex(index);
-    const newParams = { ...searchParams, worksId: item.id, current: 1 };
-    setSearchParams(newParams);
-    await loadGoods(newParams);
+    setGoods([]); // 清空列表,给予用户切换反馈 (或者可以保留旧数据直到新数据到来,取决于需求,清空通常感觉更"快"因为有反馈)
+    
+    // 异步加载数据
+    requestAnimationFrame(async () => {
+        const newParams = { ...searchParams, worksId: item.id, current: 1 };
+        setSearchParams(newParams);
+        await loadGoods(newParams);
+    });
   };
 
   // 商品点击
@@ -137,6 +147,52 @@ export default function HomeScreen() {
     router.push(`/product/${item.id}` as any);
   };
 
+  // 列表头部组件
+  const ListHeader = useMemo(() => {
+    return (
+      <>
+        {/* 搜索栏 */}
+        <SearchBar onSearch={handleSearch} />
+
+        {/* Banner 轮播 */}
+        {banners.length > 0 && <Banner data={banners} onPress={handleBannerPress} />}
+
+        {/* 功能入口 */}
+        <View style={styles.section}>
+          {tabs.length > 0 && <QuickEntry data={tabs} onPress={handleQuickEntryPress} />}
+
+          {/* IP 分类筛选 */}
+          {ipList.length > 0 && (
+            <IPFilter data={ipList} activeIndex={ipIndex} onSelect={handleIPSelect} />
+          )}
+        </View>
+      </>
+    );
+  }, [banners, tabs, ipList, ipIndex]); // 依赖项
+
+  const renderItem = useCallback(({ item }: { item: GoodsItem }) => {
+    return <GoodsCard data={item} onPress={handleGoodsPress} />;
+  }, []);
+
+  const ListEmptyComponent = useMemo(() => {
+    if (listLoading) {
+      return (
+        <View style={styles.loadingListContainer}>
+          <ActivityIndicator size="small" color="#aaa" />
+          <Text style={styles.loadingText}>加载商品中...</Text>
+        </View>
+      );
+    }
+    if (!loading && goods.length === 0) {
+        return (
+            <View style={styles.emptyContainer}>
+                <Text style={styles.emptyText}>暂无商品</Text>
+            </View>
+        )
+    }
+    return null;
+  }, [listLoading, loading, goods.length]);
+
   if (loading) {
     return (
       <View style={styles.loadingContainer}>
@@ -154,33 +210,22 @@ export default function HomeScreen() {
         style={styles.background}
         resizeMode="cover"
       >
-        <ScrollView
-          style={styles.scrollView}
-          contentContainerStyle={{ paddingTop: insets.top + 10 }}
+        <FlatList
+          data={goods}
+          renderItem={renderItem}
+          keyExtractor={(item) => item.id}
+          ListHeaderComponent={ListHeader}
+          numColumns={2}
+          columnWrapperStyle={styles.columnWrapper}
+          contentContainerStyle={{ paddingTop: insets.top + 10, paddingBottom: 20 }}
           showsVerticalScrollIndicator={false}
           refreshControl={
             <RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor="#fff" />
           }
-        >
-          {/* 搜索栏 */}
-          <SearchBar onSearch={handleSearch} />
-
-          {/* Banner 轮播 */}
-          {banners.length > 0 && <Banner data={banners} onPress={handleBannerPress} />}
-
-          {/* 功能入口 */}
-          <View style={styles.section}>
-            {tabs.length > 0 && <QuickEntry data={tabs} onPress={handleQuickEntryPress} />}
-
-            {/* IP 分类筛选 */}
-            {ipList.length > 0 && (
-              <IPFilter data={ipList} activeIndex={ipIndex} onSelect={handleIPSelect} />
-            )}
-          </View>
-
-          {/* 商品列表 */}
-          <GoodsList data={goods} onItemPress={handleGoodsPress} />
-        </ScrollView>
+          ListEmptyComponent={ListEmptyComponent}
+          onEndReachedThreshold={0.5}
+          // onEndReached={() => { /* Implement pagination if needed */ }}
+        />
       </ImageBackground>
     </View>
   );
@@ -194,9 +239,6 @@ const styles = StyleSheet.create({
   background: {
     flex: 1,
   },
-  scrollView: {
-    flex: 1,
-  },
   section: {
     paddingHorizontal: 10,
   },
@@ -206,9 +248,25 @@ const styles = StyleSheet.create({
     justifyContent: 'center',
     alignItems: 'center',
   },
+  loadingListContainer: {
+    padding: 20,
+    alignItems: 'center',
+  },
   loadingText: {
     color: '#fff',
     marginTop: 10,
     fontSize: 14,
   },
+  columnWrapper: {
+    justifyContent: 'space-between',
+    paddingHorizontal: 10,
+  },
+  emptyContainer: {
+    padding: 50,
+    alignItems: 'center',
+  },
+  emptyText: {
+    color: '#999',
+    fontSize: 14,
+  },
 });