Clean up pagination
This commit is contained in:
@@ -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') {
|
||||||
|
|||||||
@@ -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++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user