1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

made lab infinite loader with intersection observer

This commit is contained in:
Fedor Katurov 2021-10-12 16:07:51 +07:00
parent 9dbc5739b7
commit a553a06ac5
5 changed files with 63 additions and 24 deletions

View file

@ -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/

View file

@ -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<IProps> = ({ isLoading, nodes }) => {
const LabGrid: FC<IProps> = ({ isLoading, nodes, onLoadMore }) => {
const columns = useMemo(() => Array.from(document.querySelectorAll(`.${styles.column}`)), [
isLoading,
nodes,
]);
useLabPagination(isLoading, columns, onLoadMore);
if (isLoading) {
return (
<Masonry

View file

@ -10,6 +10,7 @@ div.wrap {
background-clip: padding-box;
box-sizing: border-box;
padding: 0 $gap / 2;
margin-top: -$gap / 2;
@include tablet {
padding: 0;

View file

@ -1,10 +1,10 @@
import React, { FC, useCallback, useEffect } from 'react';
import React, { FC, useCallback, useEffect, useMemo, useRef } from 'react';
import styles from './styles.module.scss';
import { Sticky } from '~/components/containers/Sticky';
import { Container } from '~/containers/main/Container';
import { LabGrid } from '~/containers/lab/LabGrid';
import { useDispatch } from 'react-redux';
import { labGetList, labGetStats } from '~/redux/lab/actions';
import { labGetList, labGetMore, labGetStats } from '~/redux/lab/actions';
import { Group } from '~/components/containers/Group';
import { LabHead } from '~/components/lab/LabHead';
import { LabStats } from '~/containers/lab/LabStats';
@ -20,16 +20,22 @@ import { useLabPagination } from '~/utils/hooks/lab/useLabPagination';
interface IProps {}
const LabLayout: FC<IProps> = () => {
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<IProps> = () => {
<LabHead isLoading={isInitialLoading} />
</div>
<LabGrid nodes={nodes} isLoading={isInitialLoading} />
<LabGrid nodes={nodes} isLoading={isInitialLoading} onLoadMore={onLoadMore} />
</Group>
<div className={styles.panel}>

View file

@ -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<IntersectionObserverCallback>(
entries => {
const isVisible = entries.some(entry => entry.intersectionRatio > 0);
const dispatch = useDispatch();
const loadMore = useCallback(() => {
if (nodes.length >= count) {
if (!isVisible) {
return;
}
dispatch(labGetMore());
}, [nodes, count]);
onLoadMore();
},
[onLoadMore]
);
useInfiniteLoader(loadMore, isLoading);
const observer = useMemo(
() =>
new IntersectionObserver(loadOnIntersection, {
threshold: [0],
}),
[loadOnIntersection]
);
useEffect(() => {
if (isLoading) {
return;
}
const lastItems = Array.from(columns)
.map(col => col.children.item(col.childNodes.length - 1))
.filter(el => el) as Element[];
lastItems.forEach(item => observer.observe(item));
return () => {
lastItems.forEach(item => observer.unobserve(item));
};
}, [observer, columns]);
};