Paginate the PostThread to avoid rendering too many posts and crashing the app on large threads (#1432)
parent
21371081c6
commit
0090371011
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue