Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
[C-1883] Use lazy tabs to improve perf (#2672)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers authored Feb 16, 2023
1 parent 4148ec4 commit dacbe0d
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 55 deletions.
20 changes: 11 additions & 9 deletions packages/mobile/src/components/lineup/Lineup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export const Lineup = ({
header,
LineupEmptyComponent,
isTrending,
lazy,
leadingElementId,
leadingElementDelineator,
lineup: lineupProp,
Expand All @@ -232,8 +233,9 @@ export const Lineup = ({
const [refreshing, setRefreshing] = useState(refreshingProp)
const selectedLineup = useSelector(lineupSelector)
const lineup = selectedLineup ?? lineupProp
const { status, entries } = lineup
const { status, entries, inView: lineupInView } = lineup
const lineupLength = entries.length
const inView = lazy ? lineupInView : true

const handleRefresh = useCallback(() => {
setRefreshing(true)
Expand Down Expand Up @@ -334,27 +336,25 @@ export const Lineup = ({

useReachableEffect(
useCallback(() => {
if (status === Status.LOADING) return
if (status === Status.LOADING || !inView) return
handleLoadMore(true)
// using the latest creates infinite loop, and we only need the initial state
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [entries])
}, [status, inView, handleLoadMore])
)

// When scrolled past the end threshold of the lineup and the lineup is not loading,
// trigger another load
useEffect(() => {
if (isPastLoadThreshold && status !== Status.LOADING) {
if (isPastLoadThreshold && status !== Status.LOADING && inView) {
setIsPastLoadThreshold(false)
handleLoadMore()
}
}, [isPastLoadThreshold, status, handleLoadMore])
}, [isPastLoadThreshold, status, handleLoadMore, inView])

useEffect(() => {
if (selfLoad && lineupLength === 0 && status !== Status.LOADING) {
if (selfLoad && status === Status.IDLE && inView) {
handleLoadMore()
}
}, [handleLoadMore, selfLoad, lineupLength, status])
}, [handleLoadMore, selfLoad, lineupLength, status, inView])

const togglePlay = useCallback(
({ uid, id, source }: TogglePlayConfig) => {
Expand Down Expand Up @@ -401,6 +401,7 @@ export const Lineup = ({

const getSkeletonCount = () => {
const shouldCalculateSkeletons =
inView &&
items.length < limit &&
// Lineup has more items to load
hasMore &&
Expand Down Expand Up @@ -456,6 +457,7 @@ export const Lineup = ({

return [{ delineate: false, data }]
}, [
inView,
count,
countOrDefault,
delineate,
Expand Down
7 changes: 7 additions & 0 deletions packages/mobile/src/components/lineup/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ export type LineupProps = {
/** Are we in a trending lineup? Allows tiles to specialize their rendering */
isTrending?: boolean

/**
* When `true` lineup waits until visible before fetching.
* This is especcially needed for lineups inside collapsible-tab-view
* which do not support tab-navigator lazy mode
*/
lazy?: boolean

/**
* Indicator if a track should be displayed differently (ie. artist pick)
* The leadingElementId is displayed at the top of the lineup
Expand Down
23 changes: 10 additions & 13 deletions packages/mobile/src/components/top-tab-bar/TopTabNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,13 @@ type TabNavigatorProps = {
screenOptions?: MaterialTopTabNavigationOptions
}

export const TabNavigator = ({
initialScreenName,
children,
screenOptions
}: TabNavigatorProps) => {
export const TabNavigator = (props: TabNavigatorProps) => {
const { initialScreenName, children, screenOptions } = props
return (
<Tab.Navigator
initialRouteName={initialScreenName}
tabBar={(props) => <TopTabBar {...props} />}
screenOptions={{
...screenOptions
}}
screenOptions={screenOptions}
>
{children}
</Tab.Navigator>
Expand Down Expand Up @@ -63,14 +58,16 @@ export const tabScreen = (config: TabScreenConfig) => {
type TopTabsProps = {
initialScreenName?: string
screens?: ScreenConfig[]
screenOptions?: MaterialTopTabNavigationOptions
}

export const TopTabNavigator = ({
initialScreenName,
screens
}: TopTabsProps) => {
export const TopTabNavigator = (props: TopTabsProps) => {
const { initialScreenName, screens, screenOptions } = props
return (
<TabNavigator initialScreenName={initialScreenName}>
<TabNavigator
initialScreenName={initialScreenName}
screenOptions={screenOptions}
>
{screens?.map((screen) => tabScreen({ key: screen.name, ...screen }))}
</TabNavigator>
)
Expand Down
5 changes: 4 additions & 1 deletion packages/mobile/src/screens/explore-screen/ExploreScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ const ExploreScreen = () => {
iconProps={{ height: 30 }}
/>
<ScreenContent>
<TopTabNavigator screens={exploreScreens} />
<TopTabNavigator
screens={exploreScreens}
screenOptions={{ lazy: true }}
/>
</ScreenContent>
</Screen>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ export const FavoritesScreen = () => {
{isOfflineModeEnabled ? <FavoritesDownloadSection /> : null}
</ScreenHeader>
<ScreenContent isOfflineCapable={isOfflineModeEnabled}>
{<TopTabNavigator screens={favoritesScreens} />}
<TopTabNavigator
screens={favoritesScreens}
screenOptions={{ lazy: true }}
/>
</ScreenContent>
</Screen>
)
Expand Down
6 changes: 2 additions & 4 deletions packages/mobile/src/screens/profile-screen/RepostsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,24 @@ import { useSelectProfile } from './selectors'
const { getProfileFeedLineup } = profilePageSelectors

export const RepostsTab = () => {
const { handle } = useSelectProfile(['handle'])
const { handle, repost_count } = useSelectProfile(['handle', 'repost_count'])
const handleLower = handle.toLowerCase()

const lineup = useProxySelector(
(state) => getProfileFeedLineup(state, handleLower),
[handleLower]
)
const { repost_count } = useSelectProfile(['repost_count'])

const extraFetchOptions = useMemo(
() => ({ handle: handleLower }),
[handleLower]
)

if (!lineup) return null

return (
<Lineup
listKey='profile-reposts'
selfLoad
lazy
actions={feedActions}
lineup={lineup}
limit={repost_count}
Expand Down
30 changes: 4 additions & 26 deletions packages/mobile/src/screens/profile-screen/TracksTab.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect } from 'react'
import { useCallback } from 'react'

import {
profilePageSelectors,
Expand All @@ -10,11 +10,10 @@ import { useDispatch } from 'react-redux'
import { Lineup } from 'app/components/lineup'

import { EmptyProfileTile } from './EmptyProfileTile'
import { useIsProfileLoaded, useSelectProfile } from './selectors'
import { useSelectProfile } from './selectors'
const { getProfileTracksLineup } = profilePageSelectors

export const TracksTab = () => {
const isProfileLoaded = useIsProfileLoaded()
const dispatch = useDispatch()

const { handle, user_id, track_count, artist_pick_track_id } =
Expand All @@ -32,45 +31,24 @@ export const TracksTab = () => {
[handleLower]
)

useEffect(() => {
if (isProfileLoaded) {
dispatch(
tracksActions.fetchLineupMetadatas(
undefined,
undefined,
undefined,
{ userId: user_id },
{ handle: handleLower }
)
)
}
}, [dispatch, isProfileLoaded, user_id, handleLower])

const loadMore = useCallback(
(offset: number, limit: number) => {
dispatch(
tracksActions.fetchLineupMetadatas(
offset,
limit,
false,
{
userId: user_id
},
{ userId: user_id },
{ handle }
)
)
},
[dispatch, user_id, handle]
)

if (!lineup) return null

/**
* If the profile isn't loaded yet, pass the lineup an empty entries
* array so only skeletons are displayed
*/
return (
<Lineup
selfLoad
leadingElementId={artist_pick_track_id}
listKey='profile-tracks'
actions={tracksActions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ export const TrendingScreen = () => {
<TrendingFilterButton />
</ScreenHeader>
<ScreenContent>
<TopTabNavigator screens={trendingScreens} />
<TopTabNavigator
screens={trendingScreens}
screenOptions={{ lazy: true }}
/>
</ScreenContent>
</Screen>
)
Expand Down

0 comments on commit dacbe0d

Please sign in to comment.