Infinite scroll: automatically load new page of results
This commit is contained in:
parent
be9df7bcd8
commit
76ffe8eea1
|
@ -4,6 +4,8 @@ import { Col } from '../layout/col'
|
||||||
import { SiteLink } from '../site-link'
|
import { SiteLink } from '../site-link'
|
||||||
import { ContractCard } from './contract-card'
|
import { ContractCard } from './contract-card'
|
||||||
import { ContractSearch } from '../contract-search'
|
import { ContractSearch } from '../contract-search'
|
||||||
|
import { useIsVisible } from 'web/hooks/use-is-visible'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
export function ContractsGrid(props: {
|
export function ContractsGrid(props: {
|
||||||
contracts: Contract[]
|
contracts: Contract[]
|
||||||
|
@ -13,6 +15,16 @@ export function ContractsGrid(props: {
|
||||||
}) {
|
}) {
|
||||||
const { contracts, showCloseTime, hasMore, loadMore } = props
|
const { contracts, showCloseTime, hasMore, loadMore } = props
|
||||||
|
|
||||||
|
const [elem, setElem] = useState<HTMLElement | null>(null)
|
||||||
|
const isBottomVisible = useIsVisible(elem)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log({ isBottomVisible, hasMore })
|
||||||
|
if (isBottomVisible) {
|
||||||
|
loadMore()
|
||||||
|
}
|
||||||
|
}, [isBottomVisible, hasMore, loadMore])
|
||||||
|
|
||||||
if (contracts.length === 0) {
|
if (contracts.length === 0) {
|
||||||
return (
|
return (
|
||||||
<p className="mx-2 text-gray-500">
|
<p className="mx-2 text-gray-500">
|
||||||
|
@ -35,14 +47,7 @@ export function ContractsGrid(props: {
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
{hasMore && (
|
<div ref={setElem} className="relative -top-96 h-1" />
|
||||||
<button
|
|
||||||
className="btn btn-primary self-center normal-case"
|
|
||||||
onClick={loadMore}
|
|
||||||
>
|
|
||||||
Show more
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,11 +59,11 @@ export function FeedItems(props: {
|
||||||
const { contract, items, className, betRowClassName } = props
|
const { contract, items, className, betRowClassName } = props
|
||||||
const { outcomeType } = contract
|
const { outcomeType } = contract
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement | null>(null)
|
const [elem, setElem] = useState<HTMLElement | null>(null)
|
||||||
useSaveSeenContract(ref, contract)
|
useSaveSeenContract(elem, contract)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flow-root', className)} ref={ref}>
|
<div className={clsx('flow-root', className)} ref={setElem}>
|
||||||
<div className={clsx(tradingAllowed(contract) ? '' : '-mb-6')}>
|
<div className={clsx(tradingAllowed(contract) ? '' : '-mb-6')}>
|
||||||
{items.map((item, activityItemIdx) => (
|
{items.map((item, activityItemIdx) => (
|
||||||
<div key={item.id} className={'relative pb-6'}>
|
<div key={item.id} className={'relative pb-6'}>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { RefObject, useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
export function useIsVisible(elementRef: RefObject<Element>) {
|
export function useIsVisible(element: HTMLElement | null) {
|
||||||
return !!useIntersectionObserver(elementRef)?.isIntersecting
|
return !!useIntersectionObserver(element)?.isIntersecting
|
||||||
}
|
}
|
||||||
|
|
||||||
function useIntersectionObserver(
|
function useIntersectionObserver(
|
||||||
elementRef: RefObject<Element>
|
elem: HTMLElement | null
|
||||||
): IntersectionObserverEntry | undefined {
|
): IntersectionObserverEntry | undefined {
|
||||||
const [entry, setEntry] = useState<IntersectionObserverEntry>()
|
const [entry, setEntry] = useState<IntersectionObserverEntry>()
|
||||||
|
|
||||||
|
@ -14,16 +14,15 @@ function useIntersectionObserver(
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const node = elementRef?.current
|
|
||||||
const hasIOSupport = !!window.IntersectionObserver
|
const hasIOSupport = !!window.IntersectionObserver
|
||||||
|
|
||||||
if (!hasIOSupport || !node) return
|
if (!hasIOSupport || !elem) return
|
||||||
|
|
||||||
const observer = new IntersectionObserver(updateEntry, {})
|
const observer = new IntersectionObserver(updateEntry, {})
|
||||||
observer.observe(node)
|
observer.observe(elem)
|
||||||
|
|
||||||
return () => observer.disconnect()
|
return () => observer.disconnect()
|
||||||
}, [elementRef])
|
}, [elem])
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { useEffect, RefObject, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { Contract } from 'common/contract'
|
import { Contract } from 'common/contract'
|
||||||
import { trackView } from 'web/lib/firebase/tracking'
|
import { trackView } from 'web/lib/firebase/tracking'
|
||||||
import { useIsVisible } from './use-is-visible'
|
import { useIsVisible } from './use-is-visible'
|
||||||
|
@ -17,10 +17,10 @@ export const useSeenContracts = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSaveSeenContract = (
|
export const useSaveSeenContract = (
|
||||||
ref: RefObject<Element>,
|
elem: HTMLElement | null,
|
||||||
contract: Contract
|
contract: Contract
|
||||||
) => {
|
) => {
|
||||||
const isVisible = useIsVisible(ref)
|
const isVisible = useIsVisible(elem)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user