Ott 337 matches lazy request (#122)
parent
bfa7a214da
commit
70d9c924f0
@ -1,15 +1,23 @@ |
|||||||
import React from 'react' |
import React from 'react' |
||||||
|
|
||||||
|
import { InfiniteScroll } from 'features/InfiniteScroll' |
||||||
import { Matches } from 'features/Matches' |
import { Matches } from 'features/Matches' |
||||||
|
|
||||||
import { useHomePage } from './hooks' |
import { useHomePage } from './hooks' |
||||||
import { Content } from './styled' |
import { Content, Loading } from './styled' |
||||||
|
|
||||||
export const HomePage = () => { |
export const HomePage = () => { |
||||||
const { matches } = useHomePage() |
const { |
||||||
|
fetchMoreMatches, |
||||||
|
isFetching, |
||||||
|
matches, |
||||||
|
} = useHomePage() |
||||||
return ( |
return ( |
||||||
<Content> |
<Content> |
||||||
<Matches matches={matches} /> |
<InfiniteScroll onFetchMore={fetchMoreMatches}> |
||||||
|
<Matches matches={matches} /> |
||||||
|
</InfiniteScroll> |
||||||
|
{isFetching && <Loading>Loading...</Loading>} |
||||||
</Content> |
</Content> |
||||||
) |
) |
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,52 @@ |
|||||||
|
import { useEffect, useRef } from 'react' |
||||||
|
|
||||||
|
import noop from 'lodash/noop' |
||||||
|
|
||||||
|
type Args = { |
||||||
|
onIntersect: ( |
||||||
|
target: IntersectionObserverEntry, |
||||||
|
observer: IntersectionObserver, |
||||||
|
) => void, |
||||||
|
options?: IntersectionObserverInit, |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Хук для отслежения пересечение targetRef с rootRef |
||||||
|
* targetRef нужно повесить на целевой элемент который будет наблюдаться, |
||||||
|
* rootRef на корневой элемент с которым пересекается targetRef. |
||||||
|
* Также можно проигнорить rootRef тогда по-умолчанию отслеживается |
||||||
|
* пересечение с областью видимости документа |
||||||
|
*/ |
||||||
|
export const useIntersectionObserver = ({ onIntersect, options }: Args) => { |
||||||
|
const rootRef = useRef<HTMLDivElement>(null) |
||||||
|
const targetRef = useRef<HTMLDivElement>(null) |
||||||
|
const rootElement = rootRef.current |
||||||
|
const targetElement = targetRef.current |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (!targetElement) { |
||||||
|
return noop |
||||||
|
} |
||||||
|
|
||||||
|
const observerOptions = { root: rootElement, ...options } |
||||||
|
const callback = ([target]: Array<IntersectionObserverEntry>) => { |
||||||
|
if (target.isIntersecting) { |
||||||
|
onIntersect(target, observer) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const observer = new IntersectionObserver(callback, observerOptions) |
||||||
|
observer.observe(targetElement) |
||||||
|
|
||||||
|
return () => { |
||||||
|
observer.disconnect() |
||||||
|
} |
||||||
|
}, [ |
||||||
|
rootElement, |
||||||
|
targetElement, |
||||||
|
onIntersect, |
||||||
|
options, |
||||||
|
]) |
||||||
|
|
||||||
|
return { rootRef, targetRef } |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
import type { ReactNode } from 'react' |
||||||
|
import React from 'react' |
||||||
|
|
||||||
|
import { useIntersectionObserver } from './hooks' |
||||||
|
import { Root, Target } from './styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
children: ReactNode, |
||||||
|
onFetchMore: () => void, |
||||||
|
options?: IntersectionObserverInit, |
||||||
|
} |
||||||
|
|
||||||
|
export const InfiniteScroll = ({ |
||||||
|
children, |
||||||
|
onFetchMore, |
||||||
|
options, |
||||||
|
}: Props) => { |
||||||
|
const { targetRef } = useIntersectionObserver({ |
||||||
|
onIntersect: onFetchMore, |
||||||
|
options, |
||||||
|
}) |
||||||
|
|
||||||
|
return ( |
||||||
|
<Root> |
||||||
|
{children} |
||||||
|
<Target ref={targetRef} /> |
||||||
|
</Root> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,8 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
export const Root = styled.div`` |
||||||
|
|
||||||
|
export const Target = styled.div` |
||||||
|
position: relative; |
||||||
|
bottom: 20vh; |
||||||
|
` |
||||||
Loading…
Reference in new issue