import { SetStateAction, useCallback, useEffect, useRef, useState } from 'react'
import useInfiniteScroll from 'react-easy-infinite-scroll-hook'
import { FixedSizeList } from 'react-window'
export const loadMore = async (length = 50): Promise<string[]> => new Promise((res) => setTimeout(() => res(createItems(length)), 1000))
export const createItems = (length = 100): string[] => {
return Array.from({ length }).map((_e, i) => `item ${i}`)
}
export const createNext =
({ setLoading, setData, offset }: { setData: (v: SetStateAction<string[]>) => void; setLoading: (v: SetStateAction<boolean>) => void; offset: number }) =>
async () => {
try {
setLoading(true)
const rows = await loadMore(offset)
setData((prev) => [...rows, ...prev])
} finally {
setLoading(false)
}
}
const ReversedVerticalList = () => {
const [data, setData] = useState<string[]>(() => createItems())
const listRef = useRef<FixedSizeList>()
const ref = useInfiniteScroll<HTMLDivElement>({
next: createNext({ setData, setLoading: () => ({}), offset: 50 }),
rowCount: data.length,
hasMore: {
up: true,
down: false,
},
scrollThreshold: '50px',
})
const setRVRef = useCallback((RVnode) => {
if (RVnode) {
ref.current = RVnode._outerRef
listRef.current = RVnode
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useEffect(() => {
listRef.current?.scrollTo(Number.MAX_SAFE_INTEGER)
}, [])
return (
<>
<FixedSizeList ref={setRVRef} width={500} height={500} itemSize={20} itemCount={data.length}>
{({ index, style }) => {
const item = data[index]
return <div style={style}>{item}</div>
}}
</FixedSizeList>
</>
)
}
export default ReversedVerticalList
const ReversedVerticalList = () => {
const [data, _setData] = useState<string[]>(() => createItems())
const listRef = useRef<FixedSizeList>()
const [initialLoad, setInitialLoad] = useState(true)
const setData = (v) => {
!initialLoad && _setData(v)
}
const ref = useInfiniteScroll<HTMLDivElement>({
next: createNext({ setData, setLoading: () => ({}), offset: 50 }),
rowCount: data.length,
hasMore: {
up: true,
down: false,
},
scrollThreshold: '50px',
})
const setRVRef = useCallback((RVnode) => {
if (RVnode) {
ref.current = RVnode._outerRef
listRef.current = RVnode
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useEffect(() => {
listRef.current?.scrollTo(Number.MAX_SAFE_INTEGER)
setInitialLoad(false)
}, [])
return (
<>
<FixedSizeList ref={setRVRef} width={500} height={500} itemSize={20} itemCount={data.length}>
{({ index, style }) => {
const item = data[index]
return <div style={style}>{item}</div>
}}
</FixedSizeList>
</>
)
}