Paginate the PostThread to avoid rendering too many posts and crashing the app on large threads (#1432)

zio/stable
Paul Frazee 2023-09-11 17:41:00 -07:00 committed by GitHub
parent 21371081c6
commit 0090371011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 33 additions and 6 deletions

View File

@ -3,6 +3,7 @@ import {runInAction} from 'mobx'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import { import {
ActivityIndicator, ActivityIndicator,
Pressable,
RefreshControl, RefreshControl,
StyleSheet, StyleSheet,
TouchableOpacity, TouchableOpacity,
@ -47,6 +48,10 @@ const CHILD_SPINNER = {
_reactKey: '__child_spinner__', _reactKey: '__child_spinner__',
_isHighlightedPost: false, _isHighlightedPost: false,
} }
const LOAD_MORE = {
_reactKey: '__load_more__',
_isHighlightedPost: false,
}
const BOTTOM_COMPONENT = { const BOTTOM_COMPONENT = {
_reactKey: '__bottom_component__', _reactKey: '__bottom_component__',
_isHighlightedPost: false, _isHighlightedPost: false,
@ -74,10 +79,14 @@ export const PostThread = observer(function PostThread({
const ref = useRef<FlatList>(null) const ref = useRef<FlatList>(null)
const hasScrolledIntoView = useRef<boolean>(false) const hasScrolledIntoView = useRef<boolean>(false)
const [isRefreshing, setIsRefreshing] = React.useState(false) const [isRefreshing, setIsRefreshing] = React.useState(false)
const [maxVisible, setMaxVisible] = React.useState(100)
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const posts = React.useMemo(() => { const posts = React.useMemo(() => {
if (view.thread) { if (view.thread) {
const arr = [TOP_COMPONENT].concat(Array.from(flattenThread(view.thread))) let arr = [TOP_COMPONENT].concat(Array.from(flattenThread(view.thread)))
if (arr.length > maxVisible) {
arr = arr.slice(0, maxVisible).concat([LOAD_MORE])
}
if (view.isLoadingFromCache) { if (view.isLoadingFromCache) {
if (view.thread?.postRecord?.reply) { if (view.thread?.postRecord?.reply) {
arr.unshift(PARENT_SPINNER) arr.unshift(PARENT_SPINNER)
@ -89,7 +98,7 @@ export const PostThread = observer(function PostThread({
return arr return arr
} }
return [] return []
}, [view.isLoadingFromCache, view.thread]) }, [view.isLoadingFromCache, view.thread, maxVisible])
useSetTitle( useSetTitle(
view.thread?.postRecord && view.thread?.postRecord &&
`${sanitizeDisplayName( `${sanitizeDisplayName(
@ -178,7 +187,7 @@ export const PostThread = observer(function PostThread({
return <ComposePrompt onPressCompose={onPressReply} /> return <ComposePrompt onPressCompose={onPressReply} />
} else if (item === DELETED) { } else if (item === DELETED) {
return ( return (
<View style={[pal.border, pal.viewLight, styles.missingItem]}> <View style={[pal.border, pal.viewLight, styles.itemContainer]}>
<Text type="lg-bold" style={pal.textLight}> <Text type="lg-bold" style={pal.textLight}>
Deleted post. Deleted post.
</Text> </Text>
@ -186,12 +195,30 @@ export const PostThread = observer(function PostThread({
) )
} else if (item === BLOCKED) { } else if (item === BLOCKED) {
return ( return (
<View style={[pal.border, pal.viewLight, styles.missingItem]}> <View style={[pal.border, pal.viewLight, styles.itemContainer]}>
<Text type="lg-bold" style={pal.textLight}> <Text type="lg-bold" style={pal.textLight}>
Blocked post. Blocked post.
</Text> </Text>
</View> </View>
) )
} else if (item === LOAD_MORE) {
return (
<Pressable
onPress={() => setMaxVisible(n => n + 50)}
style={[pal.border, pal.view, styles.itemContainer]}
accessibilityLabel="Load more posts"
accessibilityHint="">
<View
style={[
pal.viewLight,
{paddingHorizontal: 18, paddingVertical: 14, borderRadius: 6},
]}>
<Text type="lg-medium" style={pal.text}>
Load more posts
</Text>
</View>
</Pressable>
)
} else if (item === BOTTOM_COMPONENT) { } else if (item === BOTTOM_COMPONENT) {
// HACK // HACK
// due to some complexities with how flatlist works, this is the easiest way // due to some complexities with how flatlist works, this is the easiest way
@ -373,8 +400,8 @@ const styles = StyleSheet.create({
paddingVertical: 14, paddingVertical: 14,
borderRadius: 6, borderRadius: 6,
}, },
missingItem: { itemContainer: {
borderTop: 1, borderTopWidth: 1,
paddingHorizontal: 18, paddingHorizontal: 18,
paddingVertical: 18, paddingVertical: 18,
}, },