From a553a06ac53a374904112ea48f6a28ed736ad4c3 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Tue, 12 Oct 2021 16:07:51 +0700 Subject: [PATCH] made lab infinite loader with intersection observer --- .env.development | 4 +- src/containers/lab/LabGrid/index.tsx | 13 ++++- src/containers/lab/LabGrid/styles.module.scss | 1 + src/layouts/LabLayout/index.tsx | 18 ++++--- src/utils/hooks/lab/useLabPagination.ts | 51 ++++++++++++++----- 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/.env.development b/.env.development index cf60c666..589f28a1 100644 --- a/.env.development +++ b/.env.development @@ -1,3 +1,3 @@ #REACT_APP_API_HOST=http://localhost:3334/ -REACT_APP_API_HOST=https://pig.staging.vault48.org/ -REACT_APP_REMOTE_CURRENT=https://pig.staging.vault48.org/static/ +REACT_APP_API_HOST=https://pig.vault48.org/ +REACT_APP_REMOTE_CURRENT=https://pig.vault48.org/static/ diff --git a/src/containers/lab/LabGrid/index.tsx b/src/containers/lab/LabGrid/index.tsx index 6d7bcaec..7dcf0ba6 100644 --- a/src/containers/lab/LabGrid/index.tsx +++ b/src/containers/lab/LabGrid/index.tsx @@ -1,14 +1,16 @@ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import Masonry from 'react-masonry-css'; import styles from './styles.module.scss'; import { LabNode } from '~/components/lab/LabNode'; import { EMPTY_NODE, NODE_TYPES } from '~/redux/node/constants'; import { values } from 'ramda'; import { ILabNode } from '~/redux/lab/types'; +import { useLabPagination } from '~/utils/hooks/lab/useLabPagination'; interface IProps { isLoading: boolean; nodes: ILabNode[]; + onLoadMore: () => void; } const breakpointCols = { @@ -28,7 +30,14 @@ const LoadingNode = () => ( /> ); -const LabGrid: FC = ({ isLoading, nodes }) => { +const LabGrid: FC = ({ isLoading, nodes, onLoadMore }) => { + const columns = useMemo(() => Array.from(document.querySelectorAll(`.${styles.column}`)), [ + isLoading, + nodes, + ]); + + useLabPagination(isLoading, columns, onLoadMore); + if (isLoading) { return ( = () => { - const { is_loading, nodes } = useShallowSelect(selectLabList); + const { is_loading, nodes, count } = useShallowSelect(selectLabList); const dispatch = useDispatch(); - useLabPagination({ isLoading: is_loading }); - useEffect(() => { dispatch(labGetList()); dispatch(labGetStats()); }, [dispatch]); + const onLoadMore = useCallback(() => { + if (nodes.length >= count) { + return; + } + + dispatch(labGetMore()); + }, [nodes, count]); + const isInitialLoading = is_loading && !nodes.length; return ( @@ -41,7 +47,7 @@ const LabLayout: FC = () => { - +
diff --git a/src/utils/hooks/lab/useLabPagination.ts b/src/utils/hooks/lab/useLabPagination.ts index 4fb8d071..c9262fe1 100644 --- a/src/utils/hooks/lab/useLabPagination.ts +++ b/src/utils/hooks/lab/useLabPagination.ts @@ -1,21 +1,44 @@ -import { useDispatch } from 'react-redux'; -import { useCallback } from 'react'; -import { useInfiniteLoader } from '~/utils/hooks/useInfiniteLoader'; -import { labGetMore } from '~/redux/lab/actions'; -import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; -import { selectLabList } from '~/redux/lab/selectors'; +import { useCallback, useEffect, useMemo } from 'react'; -export const useLabPagination = ({ isLoading }) => { - const { nodes, count } = useShallowSelect(selectLabList); +export const useLabPagination = ( + isLoading: boolean, + columns: Element[], + onLoadMore: () => void +) => { + const loadOnIntersection = useCallback( + entries => { + const isVisible = entries.some(entry => entry.intersectionRatio > 0); - const dispatch = useDispatch(); - const loadMore = useCallback(() => { - if (nodes.length >= count) { + if (!isVisible) { + return; + } + + onLoadMore(); + }, + [onLoadMore] + ); + + const observer = useMemo( + () => + new IntersectionObserver(loadOnIntersection, { + threshold: [0], + }), + [loadOnIntersection] + ); + + useEffect(() => { + if (isLoading) { return; } - dispatch(labGetMore()); - }, [nodes, count]); + const lastItems = Array.from(columns) + .map(col => col.children.item(col.childNodes.length - 1)) + .filter(el => el) as Element[]; - useInfiniteLoader(loadMore, isLoading); + lastItems.forEach(item => observer.observe(item)); + + return () => { + lastItems.forEach(item => observer.unobserve(item)); + }; + }, [observer, columns]); };