Skip to content

Commit

Permalink
refactor(rn-entry): use flashlist to optmize perf
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Jan 22, 2025
1 parent 0c29f27 commit 9513ec0
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 42 deletions.
18 changes: 11 additions & 7 deletions apps/mobile/src/components/common/SafeNavigationScrollView.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -66,10 +67,12 @@ export const SafeNavigationScrollView: FC<SafeNavigationScrollViewProps> = ({
)
}

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()
Expand All @@ -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 (
<Stack.Screen
Expand All @@ -112,7 +115,8 @@ export const NavigationBlurEffectHeader = (props: NavigationBlurEffectHeaderProp
</TouchableOpacity>
)
: undefined,
title: props.title,

...props,
}}
/>
)
Expand Down
7 changes: 2 additions & 5 deletions apps/mobile/src/components/ui/pressable/item-pressable.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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}
Expand Down
80 changes: 52 additions & 28 deletions apps/mobile/src/modules/entry-list/entry-list.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -62,6 +66,7 @@ export function EntryList() {
function ViewEntryList({ viewId }: { viewId: FeedViewType }) {
const entryIds = useEntryIdsByView(viewId)
const viewDef = useViewDefinition(viewId)

return <EntryListScreen title={viewDef.name} entryIds={entryIds} />
}

Expand All @@ -80,6 +85,7 @@ function CategoryEntryList({ categoryName }: { categoryName: string }) {
function ListEntryList({ listId }: { listId: string }) {
const list = useList(listId)
if (!list) return null

return <EntryListScreen title={list.title} entryIds={list.entryIds ?? []} />
}

Expand All @@ -88,29 +94,50 @@ function InboxEntryList({ inboxId }: { inboxId: string }) {
const entryIds = useEntryIdsByInboxId(inboxId)
return <EntryListScreen title={inbox?.title ?? "Inbox"} entryIds={entryIds} />
}

function EntryListScreen({ title, entryIds }: { title: string; entryIds: string[] }) {
return (
<>
<Stack.Screen
options={{
headerShown: true,
headerTitle: title,
headerLeft: LeftAction,
headerRight: RightAction,
headerTransparent: true,
headerBackground: BlurEffect,
}}
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader
headerShown
title={title}
headerLeft={useCallback(
() => (
<LeftAction />
),
[],
)}
headerRight={useCallback(
() => (
<RightAction />
),
[],
)}
/>
<View className="flex-1">
<FlashList
data={entryIds}
renderItem={useTypeScriptHappyCallback(
({ item: id }) => (
<EntryItem key={id} entryId={id} />
),
[],
)}
estimatedItemSize={100}
ItemSeparatorComponent={ItemSeparator}
/>
</View>
</SafeNavigationScrollView>
)
}

<SafeNavigationScrollView contentInsetAdjustmentBehavior="automatic" withTopInset>
<View className="flex">
{entryIds.map((id) => (
<EntryItem key={id} entryId={id} />
))}
</View>
</SafeNavigationScrollView>
</>
const ItemSeparator = () => {
return (
<View
className="bg-opaque-separator mx-4"
style={{
height: StyleSheet.hairlineWidth,
}}
/>
)
}

Expand All @@ -131,10 +158,7 @@ function EntryItem({ entryId }: { entryId: string }) {
const image = media?.[0]?.url

return (
<ItemPressable
className="bg-system-background flex flex-row items-center p-4"
onPress={handlePress}
>
<ItemPressable className="flex flex-row items-center p-4" onPress={handlePress}>
<View className="flex-1 space-y-2">
<Text numberOfLines={2} className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{title}
Expand All @@ -157,7 +181,7 @@ function EntryItem({ entryId }: { entryId: string }) {

function EntryItemSkeleton() {
return (
<View className="bg-system-background flex flex-row items-center p-4">
<View className="bg-secondary-system-grouped-background flex flex-row items-center p-4">
<View className="flex flex-1 flex-col justify-between">
{/* Title skeleton */}
<View className="h-6 w-3/4 animate-pulse rounded-md bg-zinc-200 dark:bg-zinc-800" />
Expand Down
3 changes: 1 addition & 2 deletions apps/mobile/src/screens/(stack)/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<ViewSelector />
{/* <ViewSelector /> */}
<EntryList />
</>
)
Expand Down

0 comments on commit 9513ec0

Please sign in to comment.