Use new ResizeObserver hook

This commit is contained in:
schroda
2024-07-12 23:12:11 +02:00
parent f43b7af3cd
commit 40f4350cb8
4 changed files with 79 additions and 69 deletions

View File

@@ -6,7 +6,16 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import React, { ForwardedRef, forwardRef, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import React, {
ForwardedRef,
forwardRef,
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react';
import Grid, { GridTypeMap } from '@mui/material/Grid';
import Box from '@mui/material/Box';
import { GridItemProps, GridStateSnapshot, VirtuosoGrid } from 'react-virtuoso';
@@ -22,6 +31,7 @@ import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab.tsx';
import { AppStorage } from '@/util/AppStorage.ts';
import { MangaCardProps } from '@/components/manga/MangaCard.types.tsx';
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
import { useResizeObserver } from '@/util/useResizeObserver.tsx';
const GridContainer = React.forwardRef<HTMLDivElement, GridTypeMap['props']>(({ children, ...props }, ref) => (
<Grid {...props} ref={ref} container sx={{ paddingLeft: '5px', paddingRight: '13px' }}>
@@ -310,39 +320,32 @@ export const MangaGrid: React.FC<IMangaGridProps> = ({
return () => window.removeEventListener('resize', onResize);
}, []);
useEffect(() => {
if (!gridRef.current) {
return () => {};
}
useResizeObserver(
gridRef,
useCallback(
(entries, resizeObserver) => {
const gridHeight = entries[0].target.clientHeight;
const isScrollbarVisible = gridHeight > document.documentElement.clientHeight;
if (gridRef.current.offsetHeight > document.documentElement.clientHeight) {
return () => {};
}
if (isLoading) {
return;
}
const resizeObserver = new ResizeObserver((entries) => {
const gridHeight = entries[0].target.clientHeight;
const isScrollbarVisible = gridHeight > document.documentElement.clientHeight;
if (!gridHeight) {
return;
}
if (isLoading) {
return;
}
if (isScrollbarVisible) {
resizeObserver.disconnect();
return;
}
if (!gridHeight) {
return;
}
if (isScrollbarVisible) {
loadMore();
resizeObserver.disconnect();
return;
}
loadMore();
resizeObserver.disconnect();
});
resizeObserver.observe(gridRef.current);
return () => resizeObserver.disconnect();
}, [loadMore, isLoading]);
},
[gridRef, loadMore, isLoading],
),
);
const hasNoItems = !isLoading && mangas.length === 0;
if (hasNoItems) {

View File

@@ -6,10 +6,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { MouseEvent as ReactMouseEvent, useEffect, useLayoutEffect, useRef } from 'react';
import { MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef } from 'react';
import Box from '@mui/material/Box';
import { IReaderProps } from '@/typings';
import { Page } from '@/components/reader/Page';
import { useResizeObserver } from '@/util/useResizeObserver.tsx';
const findCurrentPageIndex = (wrapper: HTMLDivElement): number => {
for (let i = 0; i < wrapper.children.length; i++) {
@@ -107,24 +108,21 @@ export function HorizontalPager(props: IReaderProps) {
}
};
useLayoutEffect(() => {
const initialPageElement = pagesRef.current[initialPage];
if (!initialPageElement) {
return () => {};
}
useResizeObserver(
pagesRef.current[initialPage],
useCallback(
(_, resizeObserver) => {
const initialPageElement = pagesRef.current[initialPage];
if (!initialPageElement?.offsetHeight) {
return;
}
const resizeObserver = new ResizeObserver(() => {
if (!initialPageElement.offsetHeight) {
return;
}
initialPageElement.scrollIntoView({ inline: 'center' });
resizeObserver.disconnect();
});
resizeObserver.observe(initialPageElement);
return () => resizeObserver.disconnect();
}, [initialPage]);
initialPageElement.scrollIntoView({ inline: 'center' });
resizeObserver.disconnect();
},
[pagesRef.current[initialPage], initialPage],
),
);
useEffect(() => {
selfRef.current?.addEventListener('mousedown', dragControl);

View File

@@ -6,10 +6,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import Box from '@mui/material/Box';
import { IReaderProps } from '@/typings';
import { Page } from '@/components/reader/Page';
import { useResizeObserver } from '@/util/useResizeObserver.tsx';
const findCurrentPageIndex = (wrapper: HTMLDivElement): number => {
for (let i = 0; i < wrapper.children.length; i++) {
@@ -165,24 +166,21 @@ export function VerticalPager(props: IReaderProps) {
};
}, [go]);
useLayoutEffect(() => {
const initialPageElement = pagesRef.current[initialPage];
if (!initialPageElement) {
return () => {};
}
useResizeObserver(
pagesRef.current[initialPage],
useCallback(
(_, resizeObserver) => {
const initialPageElement = pagesRef.current[initialPage];
if (!initialPageElement?.offsetHeight) {
return;
}
const resizeObserver = new ResizeObserver(() => {
if (!initialPageElement.offsetHeight) {
return;
}
initialPageElement.scrollIntoView();
resizeObserver.disconnect();
});
resizeObserver.observe(initialPageElement);
return () => resizeObserver.disconnect();
}, [initialPage]);
initialPageElement.scrollIntoView();
resizeObserver.disconnect();
},
[pagesRef.current[initialPage], initialPage],
),
);
return (
<Box

View File

@@ -6,17 +6,28 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { RefObject, useLayoutEffect } from 'react';
import { RefObject, useLayoutEffect, useState } from 'react';
export const useResizeObserver = (
ref: RefObject<HTMLElement> | HTMLElement | undefined,
callback: ResizeObserverCallback,
): (() => void) => {
const [disconnect, setDisconnect] = useState<() => void>(() => {});
export const useResizeObserver = (ref: RefObject<HTMLElement>, callback: ResizeObserverCallback) => {
useLayoutEffect(() => {
if (!ref.current) {
const element = ref instanceof HTMLElement ? ref : ref?.current;
if (!element) {
return () => {};
}
const resizeObserver = new ResizeObserver(callback);
resizeObserver.observe(ref.current);
resizeObserver.observe(element);
setDisconnect(() => () => resizeObserver.disconnect());
return () => resizeObserver.disconnect();
}, [ref, callback]);
return disconnect;
};