From 76ce6fb1dbb77125f56c8f35a516b3362cc94c69 Mon Sep 17 00:00:00 2001 From: imeepos Date: Fri, 16 Jan 2026 17:10:22 +0800 Subject: [PATCH] fix: bug --- .vscode/extensions.json | 1 - .vscode/settings.json | 7 -- app/(tabs)/index.tsx | 169 ++++++++++++++++++++++------------------ bun.lock | 7 ++ package.json | 1 + 5 files changed, 103 insertions(+), 82 deletions(-) delete mode 100644 .vscode/extensions.json delete mode 100644 .vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index b7ed837..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1 +0,0 @@ -{ "recommendations": ["expo.vscode-expo-tools"] } diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e2798e4..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "editor.codeActionsOnSave": { - "source.fixAll": "explicit", - "source.organizeImports": "explicit", - "source.sortMembers": "explicit" - } -} diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index e80462f..bd67456 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,10 +1,12 @@ -import { Image } from 'expo-image' -import { VideoView, useVideoPlayer } from 'expo-video' -import { LinearGradient } from 'expo-linear-gradient' -import { useRouter, useLocalSearchParams } from 'expo-router' -import { StatusBar } from 'expo-status-bar' -import { useEffect, useRef, useState } from 'react' -import { useTranslation } from 'react-i18next' +import { FlashList } from '@shopify/flash-list'; +import { Image } from 'expo-image'; +import { LinearGradient } from 'expo-linear-gradient'; +import { useLocalSearchParams, useRouter } from 'expo-router'; +import { StatusBar } from 'expo-status-bar'; +import { VideoView, useVideoPlayer } from 'expo-video'; +import { memo as ReactMemo, useEffect, useRef, useState } from 'react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; import { Dimensions, Platform, @@ -14,16 +16,70 @@ import { StyleSheet, Text, View -} from 'react-native' -import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' +} from 'react-native'; +import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; -import { DownArrowIcon, PointsIcon, SearchIcon, WhiteStarIcon } from '@/components/icon' -import { HomeSkeleton } from '@/components/skeleton/HomeSkeleton' -import { useActivates } from '@/hooks/use-activates' -import { useCategories } from '@/hooks/use-categories' +import { DownArrowIcon, PointsIcon, SearchIcon, WhiteStarIcon } from '@/components/icon'; +import { HomeSkeleton } from '@/components/skeleton/HomeSkeleton'; +import { useActivates } from '@/hooks/use-activates'; +import { useCategories } from '@/hooks/use-categories'; const { width: screenWidth } = Dimensions.get('window') +// 卡片组件 - 使用 useCallback 缓存以优化 FlashList 性能 +const Card = ReactMemo(({ card, cardWidth, t, onPress }: { + card: any + cardWidth: number + t: any + onPress: (id: string) => void +}) => { + return ( + onPress(card.id)} + > + + {card.isVideo ? ( + + ) : ( + + )} + + {card.isHot ? ( + + 🔥 + {t('home.hotTemplate')} + + ) : ( + + + + {card.users}{t('home.peopleUsed')} + + + )} + + {card.title} + + + + ) +}) + // 视频预览组件 function VideoPreview({ source, style }: { source: string; style: any }) { const player = useVideoPlayer(source, (player) => { @@ -332,7 +388,7 @@ export default function HomeScreen() { )} - {/* 内容网格 */} + {/* 内容网格 - 使用 FlashList 优化性能 */} {!showLoading && !showEmptyState && !showEmptyTemplates && ( - {displayCardData.map((card, index) => ( - { - router.push({ - pathname: '/templateDetail' as any, - params: { id: card.id.toString() }, - }) - }} - > - - {card.isVideo ? ( - - ) : ( - - )} - - {card.isHot ? ( - - 🔥 - {t('home.hotTemplate')} - - ) : ( - - - - {card.users}{t('home.peopleUsed')} - - - )} - - {card.title} - - - - ))} + ( + { + router.push({ + pathname: '/templateDetail' as any, + params: { id: id.toString() }, + }) + }} + /> + )} + keyExtractor={(item) => item.id} + numColumns={2} + estimatedItemSize={cardWidth * 1.2 + 60} + showsVerticalScrollIndicator={false} + contentContainerStyle={styles.flashListContent} + scrollEventThrottle={Platform.OS === 'ios' ? 16 : 50} + /> )} @@ -622,12 +645,10 @@ const styles = StyleSheet.create({ }, card: { marginBottom: 12, + paddingHorizontal: 5, }, - cardLeft: { - marginRight: 0, - }, - cardRight: { - marginLeft: 0, + flashListContent: { + gap: 10, }, cardImageContainer: { width: '100%', diff --git a/bun.lock b/bun.lock index 97dad8c..7afde68 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,7 @@ "@react-navigation/native": "^7.1.8", "@repo/core": "1.0.2", "@repo/sdk": "1.0.7", + "@shopify/flash-list": "^1.7.3", "@stripe/react-stripe-js": "^5.4.1", "@stripe/stripe-js": "^8.5.3", "@stripe/stripe-react-native": "^0.57.0", @@ -631,6 +632,8 @@ "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + "@shopify/flash-list": ["@shopify/flash-list@1.8.3", "", { "dependencies": { "recyclerlistview": "4.2.3", "tslib": "2.8.1" }, "peerDependencies": { "@babel/runtime": "*", "react": "*", "react-native": "*" } }, "sha512-vXuj6JyuMjONVOXjEhWFeaONPuWN/53Cl2LeyeM8TZ0JzUcNU+BE6iyga1/yyJeDf0K7YPgAE/PcUX2+DM1LiA=="], + "@simplewebauthn/browser": ["@simplewebauthn/browser@13.2.2", "", {}, "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA=="], "@simplewebauthn/server": ["@simplewebauthn/server@13.2.2", "", { "dependencies": { "@hexagon/base64": "^1.1.27", "@levischuck/tiny-cbor": "^0.2.2", "@peculiar/asn1-android": "^2.3.10", "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-rsa": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", "@peculiar/asn1-x509": "^2.3.8", "@peculiar/x509": "^1.13.0" } }, "sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA=="], @@ -1823,6 +1826,8 @@ "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + "recyclerlistview": ["recyclerlistview@4.2.3", "", { "dependencies": { "lodash.debounce": "4.0.8", "prop-types": "15.8.1", "ts-object-utils": "0.0.5" }, "peerDependencies": { "react": ">= 15.2.1", "react-native": ">= 0.30.0" } }, "sha512-STR/wj/FyT8EMsBzzhZ1l2goYirMkIgfV3gYEPxI3Kf3lOnu6f7Dryhyw7/IkQrgX5xtTcDrZMqytvteH9rL3g=="], + "reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="], "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], @@ -2035,6 +2040,8 @@ "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], + "ts-object-utils": ["ts-object-utils@0.0.5", "", {}, "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="], + "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], diff --git a/package.json b/package.json index cf8d4b2..0bad404 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/elements": "^2.6.3", "@react-navigation/native": "^7.1.8", + "@shopify/flash-list": "^1.7.3", "@stripe/react-stripe-js": "^5.4.1", "@stripe/stripe-js": "^8.5.3", "@stripe/stripe-react-native": "^0.57.0",