Clean up pagination

This commit is contained in:
Eric Bailey
2025-06-04 17:11:50 -05:00
parent 3855fe7b18
commit 6c88e94c9a
2 changed files with 43 additions and 41 deletions
+37 -33
View File
@@ -30,7 +30,7 @@ import {ListFooter} from '#/components/Lists'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
const PARENT_CHUNK_SIZE = 5 const PARENT_CHUNK_SIZE = 5
const REPLIES_CHUNK_SIZE = 50 const CHILDREN_CHUNK_SIZE = 50
export function Inner({uri}: {uri: string | undefined}) { export function Inner({uri}: {uri: string | undefined}) {
const t = useTheme() const t = useTheme()
@@ -132,20 +132,22 @@ export function Inner({uri}: {uri: string | undefined}) {
*/ */
const [deferParents, setDeferParents] = useState(isNative) const [deferParents, setDeferParents] = useState(isNative)
const [maxParentCount, setMaxParentCount] = useState(PARENT_CHUNK_SIZE) const [maxParentCount, setMaxParentCount] = useState(PARENT_CHUNK_SIZE)
const [maxRepliesCount, setMaxRepliesCount] = useState(REPLIES_CHUNK_SIZE) const [maxChildrenCount, setMaxChildrenCount] = useState(CHILDREN_CHUNK_SIZE)
const hasExhaustedReplies = useRef(false) const totalParentCount = useRef(0) // recomputed below
const totalChildrenCount = useRef(thread.data.items.length) // recomputed below
const onStartReached = () => { const onStartReached = () => {
if (thread.state.isFetching) return if (thread.state.isFetching) return
// limit to 100 // prevent any state mutations if we know we're done
setMaxParentCount(n => Math.min(100, n + PARENT_CHUNK_SIZE)) if (maxParentCount >= totalParentCount.current) return
setMaxParentCount(n => n + PARENT_CHUNK_SIZE)
} }
const onEndReached = () => { const onEndReached = () => {
if (thread.state.isFetching) return if (thread.state.isFetching) return
// prevent any state mutations if we know we're done // prevent any state mutations if we know we're done
if (hasExhaustedReplies.current) return if (maxChildrenCount >= totalChildrenCount.current) return
setMaxRepliesCount(prev => prev + REPLIES_CHUNK_SIZE) setMaxChildrenCount(prev => prev + CHILDREN_CHUNK_SIZE)
} }
const slices = useMemo(() => { const slices = useMemo(() => {
@@ -153,46 +155,48 @@ export function Inner({uri}: {uri: string | undefined}) {
if (!thread.data.items.length) return results if (!thread.data.items.length) return results
let repliesCount = 0 /*
let totalRepliesCount = 0 * Pagination hack, tracks the # of items below the anchor post.
*/
let childrenCount = 0
for (let i = 0; i < thread.data.items.length; i++) { for (let i = 0; i < thread.data.items.length; i++) {
const item = thread.data.items[i] const item = thread.data.items[i]
if ('depth' in item) { /*
if (item.depth === 0) { * Handle anchor post
results.push(item) */
if (item.type === 'threadPost' && item.depth === 0) {
results.push(item)
if (!deferParents) { // Recalculate total parents current index.
const start = i - 1 totalParentCount.current = i
const limit = Math.max(0, start - maxParentCount) // Recalculate total children using (length - 1) - current index.
for (let pi = start; pi >= limit; pi--) { totalChildrenCount.current = thread.data.items.length - 1 - i
results.unshift(thread.data.items[pi])
}
}
} else if (item.depth > 0) {
totalRepliesCount++
if (repliesCount <= maxRepliesCount) { /*
results.push(item) * Walk up the parents, limiting by `maxParentCount`
repliesCount++ */
if (!deferParents) {
const start = i - 1
const limit = Math.max(0, start - maxParentCount)
for (let pi = start; pi >= limit; pi--) {
results.unshift(thread.data.items[pi])
} }
} }
} else { } else {
// ignore parents
if (item.type === 'threadPost' && item.depth < 0) continue
// can exit early if we've reached the max children count
if (childrenCount > maxChildrenCount) break
results.push(item) results.push(item)
childrenCount++
} }
} }
// TODO should really just count these during traversal, can remove isPlaceholder data after that
if (
maxRepliesCount > totalRepliesCount &&
!thread.state.isPlaceholderData
) {
hasExhaustedReplies.current = true
}
return results return results
}, [thread, deferParents, maxParentCount, maxRepliesCount]) }, [thread, deferParents, maxParentCount, maxChildrenCount])
const renderItem = ({item, index}: {item: ThreadItem; index: number}) => { const renderItem = ({item, index}: {item: ThreadItem; index: number}) => {
if (item.type === 'threadPost') { if (item.type === 'threadPost') {
+6 -8
View File
@@ -406,15 +406,13 @@ export function buildThread({
item: 'anchor', item: 'anchor',
}), }),
) )
}
if (hasSession) { if (hasSession) {
items.push( items.push({
views.skeleton({ type: 'replyComposer',
key: 'replyComposer', key: 'replyComposer',
item: 'replyComposer', })
}),
)
}
} }
for (let i = 0; i < skeletonReplies; i++) { for (let i = 0; i < skeletonReplies; i++) {