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/. * 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 Grid, { GridTypeMap } from '@mui/material/Grid';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import { GridItemProps, GridStateSnapshot, VirtuosoGrid } from 'react-virtuoso'; 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 { AppStorage } from '@/util/AppStorage.ts';
import { MangaCardProps } from '@/components/manga/MangaCard.types.tsx'; import { MangaCardProps } from '@/components/manga/MangaCard.types.tsx';
import { MangaType } from '@/lib/graphql/generated/graphql.ts'; import { MangaType } from '@/lib/graphql/generated/graphql.ts';
import { useResizeObserver } from '@/util/useResizeObserver.tsx';
const GridContainer = React.forwardRef<HTMLDivElement, GridTypeMap['props']>(({ children, ...props }, ref) => ( const GridContainer = React.forwardRef<HTMLDivElement, GridTypeMap['props']>(({ children, ...props }, ref) => (
<Grid {...props} ref={ref} container sx={{ paddingLeft: '5px', paddingRight: '13px' }}> <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); return () => window.removeEventListener('resize', onResize);
}, []); }, []);
useEffect(() => { useResizeObserver(
if (!gridRef.current) { gridRef,
return () => {}; useCallback(
} (entries, resizeObserver) => {
const gridHeight = entries[0].target.clientHeight;
const isScrollbarVisible = gridHeight > document.documentElement.clientHeight;
if (gridRef.current.offsetHeight > document.documentElement.clientHeight) { if (isLoading) {
return () => {}; return;
} }
const resizeObserver = new ResizeObserver((entries) => { if (!gridHeight) {
const gridHeight = entries[0].target.clientHeight; return;
const isScrollbarVisible = gridHeight > document.documentElement.clientHeight; }
if (isLoading) { if (isScrollbarVisible) {
return; resizeObserver.disconnect();
} return;
}
if (!gridHeight) { loadMore();
return;
}
if (isScrollbarVisible) {
resizeObserver.disconnect(); resizeObserver.disconnect();
return; },
} [gridRef, loadMore, isLoading],
),
loadMore(); );
resizeObserver.disconnect();
});
resizeObserver.observe(gridRef.current);
return () => resizeObserver.disconnect();
}, [loadMore, isLoading]);
const hasNoItems = !isLoading && mangas.length === 0; const hasNoItems = !isLoading && mangas.length === 0;
if (hasNoItems) { if (hasNoItems) {

View File

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

View File

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

View File

@@ -6,17 +6,28 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * 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(() => { useLayoutEffect(() => {
if (!ref.current) { const element = ref instanceof HTMLElement ? ref : ref?.current;
if (!element) {
return () => {}; return () => {};
} }
const resizeObserver = new ResizeObserver(callback); const resizeObserver = new ResizeObserver(callback);
resizeObserver.observe(ref.current); resizeObserver.observe(element);
setDisconnect(() => () => resizeObserver.disconnect());
return () => resizeObserver.disconnect(); return () => resizeObserver.disconnect();
}, [ref, callback]); }, [ref, callback]);
return disconnect;
}; };