From 9513ec0b1127d85bee6db552b7d1313d648f1d52 Mon Sep 17 00:00:00 2001 From: Innei Date: Wed, 22 Jan 2025 20:28:29 +0800 Subject: [PATCH] refactor(rn-entry): use flashlist to optmize perf Signed-off-by: Innei --- .../common/SafeNavigationScrollView.tsx | 18 +++-- .../ui/pressable/item-pressable.tsx | 7 +- .../src/modules/entry-list/entry-list.tsx | 80 ++++++++++++------- .../src/screens/(stack)/(tabs)/index.tsx | 3 +- 4 files changed, 66 insertions(+), 42 deletions(-) diff --git a/apps/mobile/src/components/common/SafeNavigationScrollView.tsx b/apps/mobile/src/components/common/SafeNavigationScrollView.tsx index ce3f8643a5..eeaa6d8600 100644 --- a/apps/mobile/src/components/common/SafeNavigationScrollView.tsx +++ b/apps/mobile/src/components/common/SafeNavigationScrollView.tsx @@ -1,5 +1,6 @@ import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs" import { useHeaderHeight } from "@react-navigation/elements" +import type { NativeStackNavigationOptions } from "@react-navigation/native-stack" import { router, Stack, useNavigation } from "expo-router" import type { FC, PropsWithChildren } from "react" import { createContext, useContext, useEffect, useMemo, useState } from "react" @@ -66,10 +67,12 @@ export const SafeNavigationScrollView: FC = ({ ) } -export interface NavigationBlurEffectHeaderProps { - title?: string -} -export const NavigationBlurEffectHeader = (props: NavigationBlurEffectHeaderProps) => { +export const NavigationBlurEffectHeader = ({ + blurThreshold = 0, + ...props +}: NativeStackNavigationOptions & { + blurThreshold?: number +}) => { const label = useColor("label") const canBack = useNavigation().canGoBack() @@ -82,13 +85,13 @@ export const NavigationBlurEffectHeader = (props: NavigationBlurEffectHeaderProp useEffect(() => { const id = scrollY.addListener(({ value }) => { - setOpacity(Math.min(1, Math.max(0, Math.min(1, value / 10)))) + setOpacity(Math.min(1, Math.max(0, Math.min(1, (value + blurThreshold) / 10)))) }) return () => { scrollY.removeListener(id) } - }, [scrollY]) + }, [blurThreshold, scrollY]) return ( ) : undefined, - title: props.title, + + ...props, }} /> ) diff --git a/apps/mobile/src/components/ui/pressable/item-pressable.tsx b/apps/mobile/src/components/ui/pressable/item-pressable.tsx index e507c28464..3c285bcb7f 100644 --- a/apps/mobile/src/components/ui/pressable/item-pressable.tsx +++ b/apps/mobile/src/components/ui/pressable/item-pressable.tsx @@ -1,4 +1,4 @@ -import { cn, composeEventHandlers } from "@follow/utils" +import { composeEventHandlers } from "@follow/utils" import { memo, useEffect, useState } from "react" import type { Pressable } from "react-native" import { StyleSheet } from "react-native" @@ -49,10 +49,7 @@ export const ItemPressable: typeof Pressable = memo(({ children, ...props }) => onPressOut={composeEventHandlers(props.onPressOut, () => setIsPressing(false))} onHoverIn={composeEventHandlers(props.onHoverIn, () => setIsPressing(true))} onHoverOut={composeEventHandlers(props.onHoverOut, () => setIsPressing(false))} - className={cn( - // isPressing ? "bg-system-fill" : "bg-secondary-system-grouped-background", - props.className, - )} + className={props.className} style={StyleSheet.flatten([colorStyle, props.style])} > {children} diff --git a/apps/mobile/src/modules/entry-list/entry-list.tsx b/apps/mobile/src/modules/entry-list/entry-list.tsx index 0ea79e808e..f40dd9ae1d 100644 --- a/apps/mobile/src/modules/entry-list/entry-list.tsx +++ b/apps/mobile/src/modules/entry-list/entry-list.tsx @@ -1,11 +1,15 @@ import type { FeedViewType } from "@follow/constants" +import { useTypeScriptHappyCallback } from "@follow/hooks" import { useIsFocused } from "@react-navigation/native" -import { router, Stack } from "expo-router" +import { FlashList } from "@shopify/flash-list" +import { router } from "expo-router" import { useCallback, useEffect } from "react" -import { Image, Text, View } from "react-native" +import { Image, StyleSheet, Text, View } from "react-native" -import { BlurEffect } from "@/src/components/common/BlurEffect" -import { SafeNavigationScrollView } from "@/src/components/common/SafeNavigationScrollView" +import { + NavigationBlurEffectHeader, + SafeNavigationScrollView, +} from "@/src/components/common/SafeNavigationScrollView" import { ItemPressable } from "@/src/components/ui/pressable/item-pressable" import { useSelectedFeed, @@ -62,6 +66,7 @@ export function EntryList() { function ViewEntryList({ viewId }: { viewId: FeedViewType }) { const entryIds = useEntryIdsByView(viewId) const viewDef = useViewDefinition(viewId) + return } @@ -80,6 +85,7 @@ function CategoryEntryList({ categoryName }: { categoryName: string }) { function ListEntryList({ listId }: { listId: string }) { const list = useList(listId) if (!list) return null + return } @@ -88,29 +94,50 @@ function InboxEntryList({ inboxId }: { inboxId: string }) { const entryIds = useEntryIdsByInboxId(inboxId) return } - function EntryListScreen({ title, entryIds }: { title: string; entryIds: string[] }) { return ( - <> - + ( + + ), + [], + )} + headerRight={useCallback( + () => ( + + ), + [], + )} /> + + ( + + ), + [], + )} + estimatedItemSize={100} + ItemSeparatorComponent={ItemSeparator} + /> + + + ) +} - - - {entryIds.map((id) => ( - - ))} - - - +const ItemSeparator = () => { + return ( + ) } @@ -131,10 +158,7 @@ function EntryItem({ entryId }: { entryId: string }) { const image = media?.[0]?.url return ( - + {title} @@ -157,7 +181,7 @@ function EntryItem({ entryId }: { entryId: string }) { function EntryItemSkeleton() { return ( - + {/* Title skeleton */} diff --git a/apps/mobile/src/screens/(stack)/(tabs)/index.tsx b/apps/mobile/src/screens/(stack)/(tabs)/index.tsx index 63842b4efb..28e3984dff 100644 --- a/apps/mobile/src/screens/(stack)/(tabs)/index.tsx +++ b/apps/mobile/src/screens/(stack)/(tabs)/index.tsx @@ -1,10 +1,9 @@ import { EntryList } from "@/src/modules/entry-list/entry-list" -import { ViewSelector } from "@/src/modules/feed-drawer/view-selector" export default function Index() { return ( <> - + {/* */} )