Simplify list logic further to prevent misuse (#3334)
* simplify list logic further more simplification simplify by removing `isEmpty` use `isFetchingNextPage` everywhere for clarity change `isFetching` to `isFetchingNextPage` for clarity remove some useless `useMemo`s move `renderItem` and `keyExtractor` out of component * clean bundle size check * update deploy * adjust * adjust * one test * try now * test it * done
This commit is contained in:
parent
b1bd7ab6e3
commit
8e393b16f5
12 changed files with 241 additions and 258 deletions
|
@ -368,47 +368,52 @@ export function PostThread({
|
|||
],
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
if (error || !thread) {
|
||||
return (
|
||||
<ListMaybePlaceholder
|
||||
isLoading={(!preferences || !thread) && !error}
|
||||
isError={!!error}
|
||||
noEmpty
|
||||
onRetry={refetch}
|
||||
errorTitle={error?.title}
|
||||
errorMessage={error?.message}
|
||||
/>
|
||||
{!error && thread && (
|
||||
<List
|
||||
ref={ref}
|
||||
data={posts}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
onContentSizeChange={isNative ? undefined : onContentSizeChangeWeb}
|
||||
onStartReached={onStartReached}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={2}
|
||||
onMomentumScrollEnd={onMomentumScrollEnd}
|
||||
onScrollToTop={onScrollToTop}
|
||||
maintainVisibleContentPosition={
|
||||
isNative ? MAINTAIN_VISIBLE_CONTENT_POSITION : undefined
|
||||
}
|
||||
// @ts-ignore our .web version only -prf
|
||||
desktopFixedHeight
|
||||
removeClippedSubviews={isAndroid ? false : undefined}
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
isFetching={isFetching}
|
||||
onRetry={refetch}
|
||||
// 300 is based on the minimum height of a post. This is enough extra height for the `maintainVisPos` to
|
||||
// work without causing weird jumps on web or glitches on native
|
||||
height={windowHeight - 200}
|
||||
/>
|
||||
}
|
||||
initialNumToRender={initialNumToRender}
|
||||
windowSize={11}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<List
|
||||
ref={ref}
|
||||
data={posts}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
onContentSizeChange={isNative ? undefined : onContentSizeChangeWeb}
|
||||
onStartReached={onStartReached}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={2}
|
||||
onMomentumScrollEnd={onMomentumScrollEnd}
|
||||
onScrollToTop={onScrollToTop}
|
||||
maintainVisibleContentPosition={
|
||||
isNative ? MAINTAIN_VISIBLE_CONTENT_POSITION : undefined
|
||||
}
|
||||
// @ts-ignore our .web version only -prf
|
||||
desktopFixedHeight
|
||||
removeClippedSubviews={isAndroid ? false : undefined}
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
// Using `isFetching` over `isFetchingNextPage` is done on purpose here so we get the loader on
|
||||
// initial render
|
||||
isFetchingNextPage={isFetching}
|
||||
error={cleanError(threadError)}
|
||||
onRetry={refetch}
|
||||
// 300 is based on the minimum height of a post. This is enough extra height for the `maintainVisPos` to
|
||||
// work without causing weird jumps on web or glitches on native
|
||||
height={windowHeight - 200}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
initialNumToRender={initialNumToRender}
|
||||
windowSize={11}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react'
|
||||
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
||||
import {List} from '../util/List'
|
||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {useProfileFollowersQuery} from '#/state/queries/profile-followers'
|
||||
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
||||
import {logger} from '#/logger'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||
import {useSession} from 'state/session'
|
||||
import {
|
||||
ListFooter,
|
||||
ListHeaderDesktop,
|
||||
ListMaybePlaceholder,
|
||||
} from '#/components/Lists'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useSession} from 'state/session'
|
||||
import {View} from 'react-native'
|
||||
import {List} from '../util/List'
|
||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||
|
||||
function renderItem({item}: {item: ActorDefs.ProfileViewBasic}) {
|
||||
return <ProfileCardWithFollowBtn key={item.did} profile={item} />
|
||||
|
@ -39,7 +39,6 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||
const {
|
||||
data,
|
||||
isLoading: isFollowersLoading,
|
||||
isFetching,
|
||||
isFetchingNextPage,
|
||||
hasNextPage,
|
||||
fetchNextPage,
|
||||
|
@ -47,14 +46,8 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||
refetch,
|
||||
} = useProfileFollowersQuery(resolvedDid)
|
||||
|
||||
const isError = React.useMemo(
|
||||
() => !!resolveError || !!error,
|
||||
[resolveError, error],
|
||||
)
|
||||
|
||||
const isMe = React.useMemo(() => {
|
||||
return resolvedDid === currentAccount?.did
|
||||
}, [resolvedDid, currentAccount?.did])
|
||||
const isError = !!resolveError || !!error
|
||||
const isMe = resolvedDid === currentAccount?.did
|
||||
|
||||
const followers = React.useMemo(() => {
|
||||
if (data?.pages) {
|
||||
|
@ -73,20 +66,19 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||
setIsPTRing(false)
|
||||
}, [refetch, setIsPTRing])
|
||||
|
||||
const onEndReached = async () => {
|
||||
if (isFetching || !hasNextPage || !!error) return
|
||||
const onEndReached = React.useCallback(async () => {
|
||||
if (isFetchingNextPage || !hasNextPage || !!error) return
|
||||
try {
|
||||
await fetchNextPage()
|
||||
} catch (err) {
|
||||
logger.error('Failed to load more followers', {message: err})
|
||||
}
|
||||
}
|
||||
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
|
||||
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
if (followers.length < 1) {
|
||||
return (
|
||||
<ListMaybePlaceholder
|
||||
isLoading={isDidLoading || isFollowersLoading}
|
||||
isEmpty={followers.length < 1}
|
||||
isError={isError}
|
||||
emptyType="results"
|
||||
emptyMessage={
|
||||
|
@ -97,23 +89,30 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||
errorMessage={cleanError(resolveError || error)}
|
||||
onRetry={isError ? refetch : undefined}
|
||||
/>
|
||||
{followers.length > 0 && (
|
||||
<List
|
||||
data={followers}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
refreshing={isPTRing}
|
||||
onRefresh={onRefresh}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
ListHeaderComponent={<ListHeaderDesktop title={_(msg`Followers`)} />}
|
||||
ListFooterComponent={<ListFooter isFetching={isFetchingNextPage} />}
|
||||
// @ts-ignore our .web version only -prf
|
||||
desktopFixedHeight
|
||||
initialNumToRender={initialNumToRender}
|
||||
windowSize={11}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<List
|
||||
data={followers}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
refreshing={isPTRing}
|
||||
onRefresh={onRefresh}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
ListHeaderComponent={<ListHeaderDesktop title={_(msg`Followers`)} />}
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
isFetchingNextPage={isFetchingNextPage}
|
||||
error={cleanError(error)}
|
||||
onRetry={fetchNextPage}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
// @ts-ignore our .web version only -prf
|
||||
desktopFixedHeight
|
||||
initialNumToRender={initialNumToRender}
|
||||
windowSize={11}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
import React from 'react'
|
||||
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
||||
import {List} from '../util/List'
|
||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {useProfileFollowsQuery} from '#/state/queries/profile-follows'
|
||||
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
||||
import {logger} from '#/logger'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||
import {useSession} from 'state/session'
|
||||
import {
|
||||
ListFooter,
|
||||
ListHeaderDesktop,
|
||||
ListMaybePlaceholder,
|
||||
} from '#/components/Lists'
|
||||
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||
import {useSession} from 'state/session'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {List} from '../util/List'
|
||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||
|
||||
function renderItem({item}: {item: ActorDefs.ProfileViewBasic}) {
|
||||
return <ProfileCardWithFollowBtn key={item.did} profile={item} />
|
||||
|
@ -38,7 +39,6 @@ export function ProfileFollows({name}: {name: string}) {
|
|||
const {
|
||||
data,
|
||||
isLoading: isFollowsLoading,
|
||||
isFetching,
|
||||
isFetchingNextPage,
|
||||
hasNextPage,
|
||||
fetchNextPage,
|
||||
|
@ -46,14 +46,8 @@ export function ProfileFollows({name}: {name: string}) {
|
|||
refetch,
|
||||
} = useProfileFollowsQuery(resolvedDid)
|
||||
|
||||
const isError = React.useMemo(
|
||||
() => !!resolveError || !!error,
|
||||
[resolveError, error],
|
||||
)
|
||||
|
||||
const isMe = React.useMemo(() => {
|
||||
return resolvedDid === currentAccount?.did
|
||||
}, [resolvedDid, currentAccount?.did])
|
||||
const isError = !!resolveError || !!error
|
||||
const isMe = resolvedDid === currentAccount?.did
|
||||
|
||||
const follows = React.useMemo(() => {
|
||||
if (data?.pages) {
|
||||
|
@ -72,20 +66,19 @@ export function ProfileFollows({name}: {name: string}) {
|
|||
setIsPTRing(false)
|
||||
}, [refetch, setIsPTRing])
|
||||
|
||||
const onEndReached = async () => {
|
||||
if (isFetching || !hasNextPage || !!error) return
|
||||
const onEndReached = React.useCallback(async () => {
|
||||
if (isFetchingNextPage || !hasNextPage || !!error) return
|
||||
try {
|
||||
await fetchNextPage()
|
||||
} catch (err) {
|
||||
logger.error('Failed to load more follows', {error: err})
|
||||
}
|
||||
}
|
||||
}, [error, fetchNextPage, hasNextPage, isFetchingNextPage])
|
||||
|
||||
return (
|
||||
<>
|
||||
if (follows.length < 1) {
|
||||
return (
|
||||
<ListMaybePlaceholder
|
||||
isLoading={isDidLoading || isFollowsLoading}
|
||||
isEmpty={follows.length < 1}
|
||||
isError={isError}
|
||||
emptyType="results"
|
||||
emptyMessage={
|
||||
|
@ -96,23 +89,30 @@ export function ProfileFollows({name}: {name: string}) {
|
|||
errorMessage={cleanError(resolveError || error)}
|
||||
onRetry={isError ? refetch : undefined}
|
||||
/>
|
||||
{follows.length > 0 && (
|
||||
<List
|
||||
data={follows}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
refreshing={isPTRing}
|
||||
onRefresh={onRefresh}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
ListHeaderComponent={<ListHeaderDesktop title={_(msg`Following`)} />}
|
||||
ListFooterComponent={<ListFooter isFetching={isFetchingNextPage} />}
|
||||
// @ts-ignore our .web version only -prf
|
||||
desktopFixedHeight
|
||||
initialNumToRender={initialNumToRender}
|
||||
windowSize={11}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<List
|
||||
data={follows}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
refreshing={isPTRing}
|
||||
onRefresh={onRefresh}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
ListHeaderComponent={<ListHeaderDesktop title={_(msg`Following`)} />}
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
isFetchingNextPage={isFetchingNextPage}
|
||||
error={cleanError(error)}
|
||||
onRetry={fetchNextPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
// @ts-ignore our .web version only -prf
|
||||
desktopFixedHeight
|
||||
initialNumToRender={initialNumToRender}
|
||||
windowSize={11}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue