import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet, FlatList, Image, TouchableOpacity, TextInput, SafeAreaView, StatusBar, ActivityIndicator } from 'react-native'; import Ionicons from '@expo/vector-icons/Ionicons'; import { useNavigation, useRoute } from '@react-navigation/native'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { RouteProp } from '@react-navigation/native'; import { productApi, ProductParams, type Product } from '../services/api/productApi'; // 图标组件 - 使用React.memo优化渲染 const IconComponent = React.memo(({ name, size, color }: { name: string; size: number; color: string }) => { const Icon = Ionicons as any; return ; }); // 路由参数类型 type SearchResultRouteParams = { keyword: string; }; // 产品项组件 - 使用React.memo优化渲染 const ProductItem = React.memo(({ product, onPress }: { product: Product; onPress: (product: Product) => void; }) => ( onPress(product)} activeOpacity={0.7} > {product.product_image_urls[0] ? ( ) : ( product picture )} {product.subject}{product.min_price.toFixed(2)} {product.subject_trans} Monthly Sales: {product.min_price} )); export const SearchResultScreen = () => { const navigation = useNavigation>(); const route = useRoute, string>>(); const [searchText, setSearchText] = useState(''); const [products, setProducts] = useState([]); const [loading, setLoading] = useState(true); // 初始化搜索关键字 useEffect(() => { if (route.params?.keyword) { setSearchText(route.params.keyword); searchProducts(route.params.keyword); } }, [route.params?.keyword]); // 模拟搜索产品的API调用 const searchProducts = useCallback(async (keyword: string) => { setLoading(true); try { // 这里实际项目中应替换为真实的API调用 // await apiService.search(keyword) const res = await productApi.getSearchProducts({ keyword, page: 1, page_size: 20, sort_order: 'desc' }) setProducts(res.products); } catch (error) { console.error('Error searching products:', error); // 在实际应用中应该显示错误消息 } finally { setLoading(false); } }, []); // 处理搜索提交 const handleSearch = useCallback(() => { if (searchText.trim()) { searchProducts(searchText.trim()); } }, [searchText, searchProducts]); // 处理点击产品 const handleProductPress = useCallback((product: Product) => { // 导航到产品详情页,并传递产品信息 navigation.navigate('ProductDetail', { offer_id: product.offer_id, searchKeyword: searchText, price: product.min_price }); }, [navigation, searchText]); // 返回上一页 const goBack = useCallback(() => { navigation.goBack(); }, [navigation]); // 渲染列表为空时的组件 const renderEmptyList = useCallback(() => ( No results found for "{searchText}" Try using different keywords or check your spelling ), [searchText]); // 渲染产品项 const renderProductItem = useCallback(({ item }: { item: Product }) => ( ), [handleProductPress]); return ( {/* 搜索栏 */} {searchText.length > 0 && ( setSearchText('')}> )} {/* 搜索结果 */} {/* 搜索结果标题栏 */} {loading ? 'Searching...' : `Results for "${searchText}"`} {loading ? '' : `${products.length} items found`} {/* 加载指示器 */} {loading ? ( ) : ( String(item.offer_id)} numColumns={2} contentContainerStyle={styles.productGrid} ListEmptyComponent={renderEmptyList} showsVerticalScrollIndicator={false} initialNumToRender={8} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={true} /> )} ); }; const styles = StyleSheet.create({ safeArea: { flex: 1, backgroundColor: '#ffffff', }, container: { flex: 1, backgroundColor: '#f5f5f5', }, searchHeader: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 15, paddingVertical: 10, backgroundColor: '#fff', borderBottomWidth: 1, borderBottomColor: '#f0f0f0', }, backButton: { marginRight: 10, padding: 5, }, searchBar: { flex: 1, flexDirection: 'row', alignItems: 'center', backgroundColor: '#f5f5f5', borderRadius: 20, paddingHorizontal: 15, height: 40, }, searchInput: { flex: 1, marginLeft: 8, fontSize: 16, color: '#333', height: 40, }, resultsContainer: { flex: 1, }, resultsHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 15, backgroundColor: '#fff', borderBottomWidth: 1, borderBottomColor: '#f0f0f0', }, resultsTitle: { fontSize: 16, fontWeight: 'bold', color: '#333', }, resultsCount: { fontSize: 14, color: '#999', }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, productGrid: { padding: 8, }, productCard: { flex: 1, margin: 8, backgroundColor: '#fff', borderRadius: 8, overflow: 'hidden', elevation: 2, // Android shadow shadowColor: '#000', // iOS shadow shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, }, productImageContainer: { height: 150, backgroundColor: '#f9f9f9', alignItems: 'center', justifyContent: 'center', }, productImage: { width: '100%', height: '100%', }, placeholderText: { color: '#999', fontSize: 16, }, productInfo: { padding: 10, }, productPrice: { fontSize: 18, fontWeight: 'bold', color: '#ff6600', marginBottom: 5, }, productTitle: { fontSize: 14, color: '#333', marginBottom: 5, }, productSales: { fontSize: 12, color: '#999', }, emptyContainer: { flex: 1, minHeight: 300, justifyContent: 'center', alignItems: 'center', padding: 20, }, emptyText: { fontSize: 16, fontWeight: 'bold', color: '#333', marginTop: 15, marginBottom: 8, }, emptySubtext: { fontSize: 14, color: '#999', textAlign: 'center', }, });