mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
fixed glitches due to IntersectionObserver
This commit is contained in:
@@ -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'}`}
|
||||
|
||||
@@ -193,7 +193,7 @@ const usePaginatedPlayers = (
|
||||
return;
|
||||
}
|
||||
if (shouldAppend.current) {
|
||||
setPlayers((_players) => [..._players, ...fetchedPlayers]);
|
||||
setPlayers((p) => [...p, ...fetchedPlayers]);
|
||||
shouldAppend.current = false;
|
||||
} else {
|
||||
setPlayers(fetchedPlayers);
|
||||
|
||||
20
packages/web/lib/hooks/useIsSticky.tsx
Normal file
20
packages/web/lib/hooks/useIsSticky.tsx
Normal 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;
|
||||
};
|
||||
19
packages/web/lib/hooks/useOnScreen.tsx
Normal file
19
packages/web/lib/hooks/useOnScreen.tsx
Normal 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;
|
||||
};
|
||||
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user