POWR/components/profile/ProfileFeed.tsx
DocNR c441c5afa5 feat(profile): Improve profile loading performance with tiered display system
- Add ultra-early content display after just 500ms with ANY data available
- Implement progressive content loading with three-tier timeout system
- Reduce timeouts from 5s to 4s on Android and 4s to 3s on iOS
- Enhance render state logic to prioritize partial content display
- Improve parallel data loading for all profile elements
- Add multiple fallback timers to ensure content always displays
- Update CHANGELOG.md with detailed performance improvements

This commit dramatically improves perceived performance by showing content
as soon as it becomes available rather than waiting for complete data load.
2025-04-04 22:43:03 -04:00

108 lines
3.3 KiB
TypeScript

// components/profile/ProfileFeed.tsx
import React, { useCallback, useMemo } from 'react';
import { View, FlatList, RefreshControl } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import EmptyFeed from '@/components/social/EmptyFeed';
import EnhancedSocialPost from '@/components/social/EnhancedSocialPost';
import { convertToLegacyFeedItem } from '@/lib/hooks/useProfilePageData';
import type { AnyFeedEntry } from '@/types/feed';
import ProfileHeader from './ProfileHeader';
import { NDKUser } from '@nostr-dev-kit/ndk';
interface ProfileFeedProps {
feedEntries: AnyFeedEntry[];
isRefreshing: boolean;
onRefresh: () => void;
onPostPress: (entry: AnyFeedEntry) => void;
user: NDKUser | null;
bannerImageUrl?: string;
defaultBannerUrl?: string;
followersCount: number;
followingCount: number;
refreshStats: () => Promise<void>;
isStatsLoading: boolean;
}
/**
* Profile feed component that displays the user's posts
* Pure presentational component with performance optimizations
*/
const ProfileFeed: React.FC<ProfileFeedProps> = ({
feedEntries,
isRefreshing,
onRefresh,
onPostPress,
user,
bannerImageUrl,
defaultBannerUrl,
followersCount,
followingCount,
refreshStats,
isStatsLoading,
}) => {
const insets = useSafeAreaInsets();
// Performance optimization: memoize item renderer
const renderItem = useCallback(({ item }: { item: AnyFeedEntry }) => (
<EnhancedSocialPost
item={convertToLegacyFeedItem(item)}
onPress={() => onPostPress(item)}
/>
), [onPostPress]);
// Performance optimization: memoize key extractor
const keyExtractor = useCallback((item: AnyFeedEntry) => item.id, []);
// Performance optimization: memoize header component
const ListHeaderComponent = useMemo(() => (
<ProfileHeader
user={user}
bannerImageUrl={bannerImageUrl}
defaultBannerUrl={defaultBannerUrl}
followersCount={followersCount}
followingCount={followingCount}
refreshStats={refreshStats}
isStatsLoading={isStatsLoading}
/>
), [user, bannerImageUrl, defaultBannerUrl, followersCount, followingCount, refreshStats, isStatsLoading]);
// Performance optimization: memoize empty component
const ListEmptyComponent = useMemo(() => (
<View className="px-4 py-8">
<EmptyFeed message="No posts yet. Share your workouts or create posts to see them here." />
</View>
), []);
// Performance optimization: memoize content container style
const contentContainerStyle = useMemo(() => ({
paddingBottom: insets.bottom + 20,
flexGrow: feedEntries.length === 0 ? 1 : undefined
}), [insets.bottom, feedEntries.length]);
return (
<FlatList
data={feedEntries}
keyExtractor={keyExtractor}
renderItem={renderItem}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
onRefresh={onRefresh}
/>
}
ListHeaderComponent={ListHeaderComponent}
ListEmptyComponent={ListEmptyComponent}
contentContainerStyle={contentContainerStyle}
// Performance optimizations for FlatList
removeClippedSubviews={true}
maxToRenderPerBatch={5}
initialNumToRender={8}
windowSize={5}
updateCellsBatchingPeriod={50}
/>
);
};
export default ProfileFeed;