fixed glitches due to IntersectionObserver

This commit is contained in:
dan13ram
2021-07-08 17:09:09 +05:30
committed by Alec LaLonde
parent cd6ab4118e
commit 1fa9085170
5 changed files with 56 additions and 37 deletions

View File

@@ -29,6 +29,7 @@ import {
QueryVariableSetter,
useFiltersUsed,
} from 'lib/hooks/players';
import { useIsSticky } from 'lib/hooks/useIsSticky';
import React, { useEffect, useRef, useState } from 'react';
import { SkillOption } from 'utils/skillHelpers';
@@ -124,23 +125,10 @@ export const PlayerFilter: React.FC<Props> = ({
const filtersUsed = useFiltersUsed(queryVariables);
const isSearchUsed = queryVariables.search !== '%%';
const searchText =
queryVariables.search?.substr(1, queryVariables.search.length - 2) || '';
const searchText = queryVariables.search?.slice(1, -1) || '';
const [isElementSticky, setIsSticky] = useState<boolean>(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const cachedRef = ref.current as Element;
const observer = new IntersectionObserver(
([e]) => setIsSticky(e.intersectionRatio < 1),
{ threshold: [1] },
);
observer.observe(cachedRef);
return () => observer.unobserve(cachedRef);
}, []);
const filterRef = useRef<HTMLDivElement>(null);
const isElementSticky = useIsSticky(filterRef);
const isSmallScreen = useBreakpointValue({ base: true, md: false });
const isSticky = !isSmallScreen && isElementSticky;
@@ -227,12 +215,12 @@ export const PlayerFilter: React.FC<Props> = ({
w={isSticky ? 'calc(100% + 6rem)' : '100%'}
maxW={isSticky ? 'auto' : '79rem'}
transition="all 0.25s"
bg={isElementSticky ? 'purpleTag70' : 'whiteAlpha.200'}
bg={isSticky ? 'purpleTag70' : 'whiteAlpha.200'}
py="6"
px={isSticky ? '4.5rem' : '1.5rem'}
style={{ backdropFilter: 'blur(7px)' }}
borderRadius={isSticky ? '0px' : '6px'}
ref={ref}
ref={filterRef}
position={isSmallScreen ? 'relative' : 'sticky'}
top="-1px"
borderTop="1px solid transparent"
@@ -378,7 +366,7 @@ export const PlayerFilter: React.FC<Props> = ({
</Button>
</Flex>
)}
{(fetchingMore ? totalCount > 0 : !fetching) && (
{(fetchingMore || !fetching) && (
<Flex justify="space-between" w="100%" maxW="80rem" px="4">
<Text fontWeight="bold" fontSize="xl" w="100%" maxW="79rem">
{`${totalCount} player${totalCount === 1 ? '' : 's'}`}

View File

@@ -193,7 +193,7 @@ const usePaginatedPlayers = (
return;
}
if (shouldAppend.current) {
setPlayers((_players) => [..._players, ...fetchedPlayers]);
setPlayers((p) => [...p, ...fetchedPlayers]);
shouldAppend.current = false;
} else {
setPlayers(fetchedPlayers);

View File

@@ -0,0 +1,20 @@
import { RefObject, useEffect, useState } from 'react';
export const useIsSticky = (ref: RefObject<HTMLDivElement>): boolean => {
const [isSticky, setIsSticky] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => setIsSticky(entry.intersectionRatio < 1),
{ threshold: [1] },
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
observer.disconnect();
};
}, [ref]);
return isSticky;
};

View File

@@ -0,0 +1,19 @@
import { RefObject, useEffect, useState } from 'react';
export const useOnScreen = (ref: RefObject<HTMLDivElement>): boolean => {
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) =>
setIntersecting(entry.isIntersecting),
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
observer.disconnect();
};
}, [ref]);
return isIntersecting;
};

View File

@@ -6,6 +6,7 @@ import { HeadComponent } from 'components/Seo';
import { getSsrClient } from 'graphql/client';
import { getPlayerFilters, getPlayersWithCount } from 'graphql/getPlayers';
import { usePlayerFilter } from 'lib/hooks/players';
import { useOnScreen } from 'lib/hooks/useOnScreen';
import { InferGetStaticPropsType } from 'next';
import React, { useCallback, useEffect, useRef } from 'react';
@@ -47,25 +48,16 @@ const Players: React.FC<Props> = () => {
const loaderRef = useRef<HTMLDivElement>(null);
const loadMore = useCallback(
(entries) => {
if (entries[0].isIntersecting) {
nextPage();
}
},
[nextPage],
);
const onScreen = useOnScreen(loaderRef);
const loadMore = useCallback(() => {
if (onScreen && !fetching) {
nextPage();
}
}, [nextPage, fetching, onScreen]);
useEffect(() => {
const cachedRef = loaderRef.current as Element;
const observer = new IntersectionObserver(loadMore, {
threshold: 0.25,
rootMargin: '100%',
});
observer.observe(cachedRef);
return () => observer.unobserve(cachedRef);
loadMore();
}, [loadMore]);
return (