import React, {useState, useEffect, useCallback, memo} from "react"; import { View, Text, StyleSheet, SafeAreaView, Image, StatusBar, TouchableOpacity, ScrollView, } from "react-native"; import Colors from "@/constants/Colors"; import {responsiveFontSize} from "@/utils/Responsive"; import {useRouter} from "expo-router"; import BannerSlider from "@/components/home/BannerSlider"; import BannerSkeleton from "@/components/skeleton/home/bannerSkeleton"; import CategorySkeleton from "@/components/skeleton/home/categorySkeleton"; import Sidebar from "@/components/Sidebar"; import {MenuIcon} from "@/assets/icons/index"; import {useAuth} from "@/context/AuthContext"; import {fetchAllBanners, fetchCategoryList} from "@/lib/api"; interface Category { categoryId: string; name: string; image?: string; parentCategoryId: string | null; } interface Banner { id: string; image: string; } const CategoryItem: React.FC<{ item: Category; onPress: (categoryId: string) => void; }> = memo(({item, onPress}) => { return ( <TouchableOpacity activeOpacity={1} onPress={() => onPress(item.categoryId)} > <View style={{ width: responsiveFontSize(28), height: responsiveFontSize(34), }} > <View style={styles.categoryItem}> {item.image ? ( <Image source={{uri: item.image}} style={styles.categoryImage} resizeMode="contain" /> ) : ( <View style={styles.categoryImagePlaceholder} /> )} </View> <Text style={styles.categoryTitle}>{item.name}</Text> </View> </TouchableOpacity> ); }); const HomeUserScreen: React.FC = () => { const router = useRouter(); const {userRole} = useAuth(); const [isSidebarOpen, setIsSidebarOpen] = useState<boolean>(false); const [allBanners, setAllBanners] = useState<Banner[]>([]); const [isFetchingBanners, setIsFetchingBanners] = useState<boolean>(false); const [isFetchingCategories, setIsFetchingCategories] = useState<boolean>(false); const [categories, setCategories] = useState<Category[]>([]); useEffect(() => { const fetchBanners = async () => { setIsFetchingBanners(true); try { const bannersResponse = await fetchAllBanners(); setAllBanners(bannersResponse.data); } catch (error) { console.error("Error fetching banners:", error); } finally { setIsFetchingBanners(false); } }; fetchBanners(); }, []); useEffect(() => { const fetchCategories = async () => { setIsFetchingCategories(true); try { const categoriesResponse = await fetchCategoryList(); setCategories(categoriesResponse.data); categoriesResponse.data.forEach((category: Category) => { if (category.image) { Image.prefetch(category.image); } }); } catch (error) { console.error("Error fetching categories:", error); } finally { setIsFetchingCategories(false); } }; fetchCategories(); }, []); const navigateToProduct = useCallback( (categoryId: string) => { router.push({pathname: "/product/[id]", params: {id: categoryId}}); }, [router] ); return ( <SafeAreaView style={styles.safeArea}> <StatusBar barStyle="light-content" backgroundColor={Colors.primary} /> <Sidebar isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} /> <View style={styles.header}> <TouchableOpacity onPress={() => setIsSidebarOpen(true)} style={styles.menuButton} > <MenuIcon /> </TouchableOpacity> <Text style={styles.headerTitle}>خانه</Text> </View> <> {isFetchingBanners ? ( <BannerSkeleton /> ) : ( <BannerSlider data={allBanners} /> )} {isFetchingCategories ? ( <CategorySkeleton /> ) : ( <ScrollView style={styles.pageContainer} showsVerticalScrollIndicator={false} > {categories .filter((category) => category.parentCategoryId === null) .map((category) => ( <View key={category.categoryId} style={styles.categorySection}> <Text style={styles.categorySectionTitle}> {category.name} </Text> <ScrollView horizontal={true} showsHorizontalScrollIndicator={false} contentContainerStyle={styles.horizontalScroll} showsVerticalScrollIndicator={false} > {categories .filter( (subcategory) => subcategory.parentCategoryId === category.categoryId ) .map((subcategory) => ( <CategoryItem key={subcategory.categoryId} item={subcategory} onPress={navigateToProduct} /> ))} </ScrollView> </View> ))} </ScrollView> )} </> </SafeAreaView> ); };
SOIM在菜单上工作,其中有类别和子类别,子类别是可折叠的,并且可折叠的动画使我的问题立即提供了固定的高度。
在这个新应用程序中,我正在使用一个
React 中是否有与 React Native 中的 FlatList 组件等效的组件?在 React Native 中构建了一个移动应用程序后,我现在将其转换为 React 的 Web 应用程序。 (考虑过使用react-na...
我有一个 ListHeaderComponent,里面有一个水平 FlatList,但未正确渲染。 (它只会在我热重载时呈现)。 这是我的代码 数据获取 const getData = 异步 (...
使用 TanStack Query 更新 React Native 中的搜索状态时防止不必要的重新渲染
我正在 React Native 中开发一个屏幕,其中列出了使用 TanStack 查询从我的 API 获取的书籍。我还实现了一个搜索功能,可以根据输入的文本更新结果(
从 React Native 中的 Flatlist 数据中区分前一个元素和当前元素
我正在尝试使用 React Native 构建一个聊天应用程序。我正在使用 flatlist 列出对话的消息。 导出默认类ExampleConversation扩展React.Component { _渲染它...
在“Flatlist”中追加数据,无需在React Native中刷新完整的“Flatlist”
FlatList 提供了当 listview 到达末尾时从 API 获取下一组数据的选项,我们也可以使用scrollTo 函数来保留 Flatlist 的最后滚动位置,但是
我目前正在创建一个入门屏幕,它只是几个通过单击按钮线性导航到下一个组件的组件。 不过我发现我可以使用平面列表来更好地设计它的样式......
更改棒上的平面列表ListHeaderComponentStyle
我正在制作一个简单的反应原生购物清单应用程序。我正在 FlatList 中渲染所有内容,如代码所示。我想在标头组件粘住时更改 ListHeaderComponentStyle 。 ...
这是我的代码的概要: { 处理SheetChanges(索引); 如果(索引 === 1){
Scrollview嵌套多Flashlist滚动异常React Native
这是我的代码,ScrollView 两个 FlashList 嵌套, 如果我不限制FlashList高度,它将在第一时间渲染所有项目。 如果我使用视图元素来包裹它们,滚动将在...时停止
使用 React Native 平面列表和粘性标题渲染行中的项目
我正在使用 React Native Flat List 来渲染带有粘性标题的列表。看起来粘性标题和列表项都位于同一个容器中,从而阻止我添加 flexDir...
Flatlist 在状态更新时滚动到顶部 onEndReached
我在每个TabView中都有TabView和Flatlists。在 flatlist prop onReachEnd 中,调用一个函数来更新状态。一旦执行 onRecahEnd,即使我不是
我正在使用expo、nativewind 和react native。 我正在构建一个用户个人资料页面。 问题是我无法得到一个完全符合我想要做的解决方案。 我希望整个页面可以滚动...
Flatlist 或其他包含 Scroll 的元素的渲染问题
我有一个使用 Expo Router 开发的带有选项卡系统的应用程序。在其中一个选项卡内,我配置了从选项卡的根路径到特定子路径的重定向。下面是代码调用...
使用 React Navigation 时,FlatList 和 ScrollView 不会随 React Native Web 一起滚动
使用 FlatList 推送 React 导航堆栈的屏幕将破坏 Web 上的滚动支持。 尝试了几种建议的解决方案 - 这些都不起作用: 包括带有 flex pr 的父视图...