diff --git a/src/components/MangaGrid.tsx b/src/components/MangaGrid.tsx index f4468802..e37d1674 100644 --- a/src/components/MangaGrid.tsx +++ b/src/components/MangaGrid.tsx @@ -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(({ children, ...props }, ref) => ( @@ -310,39 +320,32 @@ export const MangaGrid: React.FC = ({ 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) { diff --git a/src/components/reader/pager/HorizontalPager.tsx b/src/components/reader/pager/HorizontalPager.tsx index 5004a533..c04fc3a2 100644 --- a/src/components/reader/pager/HorizontalPager.tsx +++ b/src/components/reader/pager/HorizontalPager.tsx @@ -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); diff --git a/src/components/reader/pager/VerticalPager.tsx b/src/components/reader/pager/VerticalPager.tsx index 06874956..45d3d83a 100644 --- a/src/components/reader/pager/VerticalPager.tsx +++ b/src/components/reader/pager/VerticalPager.tsx @@ -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 ( | HTMLElement | undefined, + callback: ResizeObserverCallback, +): (() => void) => { + const [disconnect, setDisconnect] = useState<() => void>(() => {}); -export const useResizeObserver = (ref: RefObject, 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; };