1
0
Fork 0
mirror of https://github.com/Sonarr/Sonarr synced 2024-12-21 23:33:00 +00:00

useMeasure instead of Measure in TypeScript components

This commit is contained in:
Mark McDowall 2024-12-20 16:10:24 -08:00
parent a500f4ed14
commit 251f3a89b9
No known key found for this signature in database
3 changed files with 35 additions and 44 deletions

View file

@ -1,10 +1,9 @@
import moment from 'moment'; import moment from 'moment';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState'; import AppState from 'App/State/AppState';
import * as commandNames from 'Commands/commandNames'; import * as commandNames from 'Commands/commandNames';
import Measure from 'Components/Measure';
import FilterMenu from 'Components/Menu/FilterMenu'; import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent'; import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody'; import PageContentBody from 'Components/Page/PageContentBody';
@ -12,6 +11,7 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton'; import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection'; import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import useMeasure from 'Helpers/Hooks/useMeasure';
import { align, icons } from 'Helpers/Props'; import { align, icons } from 'Helpers/Props';
import NoSeries from 'Series/NoSeries'; import NoSeries from 'Series/NoSeries';
import { import {
@ -96,27 +96,13 @@ function CalendarPage() {
const customFilters = useSelector(createCustomFiltersSelector('calendar')); const customFilters = useSelector(createCustomFiltersSelector('calendar'));
const hasSeries = !!useSelector(createSeriesCountSelector()); const hasSeries = !!useSelector(createSeriesCountSelector());
const [pageContentRef, { width }] = useMeasure();
const [isCalendarLinkModalOpen, setIsCalendarLinkModalOpen] = useState(false); const [isCalendarLinkModalOpen, setIsCalendarLinkModalOpen] = useState(false);
const [isOptionsModalOpen, setIsOptionsModalOpen] = useState(false); const [isOptionsModalOpen, setIsOptionsModalOpen] = useState(false);
const [width, setWidth] = useState(0);
const isMeasured = width > 0; const isMeasured = width > 0;
const PageComponent = hasSeries ? Calendar : NoSeries; const PageComponent = hasSeries ? Calendar : NoSeries;
const handleMeasure = useCallback(
({ width: newWidth }: { width: number }) => {
setWidth(newWidth);
const dayCount = Math.max(
3,
Math.min(7, Math.floor(newWidth / MINIMUM_DAY_WIDTH))
);
dispatch(setCalendarDaysCount({ dayCount }));
},
[dispatch]
);
const handleGetCalendarLinkPress = useCallback(() => { const handleGetCalendarLinkPress = useCallback(() => {
setIsCalendarLinkModalOpen(true); setIsCalendarLinkModalOpen(true);
}, []); }, []);
@ -152,6 +138,19 @@ function CalendarPage() {
[dispatch] [dispatch]
); );
useEffect(() => {
if (width === 0) {
return;
}
const dayCount = Math.max(
3,
Math.min(7, Math.floor(width / MINIMUM_DAY_WIDTH))
);
dispatch(setCalendarDaysCount({ dayCount }));
}, [width, dispatch]);
return ( return (
<PageContent title={translate('Calendar')}> <PageContent title={translate('Calendar')}>
<PageToolbar> <PageToolbar>
@ -200,13 +199,11 @@ function CalendarPage() {
</PageToolbar> </PageToolbar>
<PageContentBody <PageContentBody
ref={pageContentRef}
className={styles.calendarPageBody} className={styles.calendarPageBody}
innerClassName={styles.calendarInnerPageBody} innerClassName={styles.calendarInnerPageBody}
> >
<Measure whitelist={['width']} onMeasure={handleMeasure}> {isMeasured ? <PageComponent totalItems={0} /> : <div />}
{isMeasured ? <PageComponent totalItems={0} /> : <div />}
</Measure>
{hasSeries && <Legend />} {hasSeries && <Legend />}
</PageContentBody> </PageContentBody>

View file

@ -13,11 +13,11 @@ import { Manager, Popper, Reference } from 'react-popper';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Measure from 'Components/Measure';
import Modal from 'Components/Modal/Modal'; import Modal from 'Components/Modal/Modal';
import ModalBody from 'Components/Modal/ModalBody'; import ModalBody from 'Components/Modal/ModalBody';
import Portal from 'Components/Portal'; import Portal from 'Components/Portal';
import Scroller from 'Components/Scroller/Scroller'; import Scroller from 'Components/Scroller/Scroller';
import useMeasure from 'Helpers/Hooks/useMeasure';
import { icons, scrollDirections, sizes } from 'Helpers/Props'; import { icons, scrollDirections, sizes } from 'Helpers/Props';
import ArrayElement from 'typings/Helpers/ArrayElement'; import ArrayElement from 'typings/Helpers/ArrayElement';
import { EnhancedSelectInputChanged, InputChanged } from 'typings/inputs'; import { EnhancedSelectInputChanged, InputChanged } from 'typings/inputs';
@ -160,13 +160,13 @@ function EnhancedSelectInput<T extends EnhancedSelectInputValue<V>, V>(
onOpen, onOpen,
} = props; } = props;
const [measureRef, { width }] = useMeasure();
const updater = useRef<(() => void) | null>(null); const updater = useRef<(() => void) | null>(null);
const buttonId = useMemo(() => getUniqueElementId(), []); const buttonId = useMemo(() => getUniqueElementId(), []);
const optionsId = useMemo(() => getUniqueElementId(), []); const optionsId = useMemo(() => getUniqueElementId(), []);
const [selectedIndex, setSelectedIndex] = useState( const [selectedIndex, setSelectedIndex] = useState(
getSelectedIndex(value, values) getSelectedIndex(value, values)
); );
const [width, setWidth] = useState(0);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const isMobile = useMemo(() => isMobileUtil(), []); const isMobile = useMemo(() => isMobileUtil(), []);
@ -381,13 +381,6 @@ function EnhancedSelectInput<T extends EnhancedSelectInputValue<V>, V>(
] ]
); );
const handleMeasure = useCallback(
({ width: newWidth }: { width: number }) => {
setWidth(newWidth);
},
[setWidth]
);
const handleOptionsModalClose = useCallback(() => { const handleOptionsModalClose = useCallback(() => {
setIsOpen(false); setIsOpen(false);
}, [setIsOpen]); }, [setIsOpen]);
@ -421,7 +414,7 @@ function EnhancedSelectInput<T extends EnhancedSelectInputValue<V>, V>(
<Reference> <Reference>
{({ ref }) => ( {({ ref }) => (
<div ref={ref} id={buttonId}> <div ref={ref} id={buttonId}>
<Measure whitelist={['width']} onMeasure={handleMeasure}> <div ref={measureRef}>
{isEditable && typeof value === 'string' ? ( {isEditable && typeof value === 'string' ? (
<div className={styles.editableContainer}> <div className={styles.editableContainer}>
<TextInput <TextInput
@ -495,7 +488,7 @@ function EnhancedSelectInput<T extends EnhancedSelectInputValue<V>, V>(
</div> </div>
</Link> </Link>
)} )}
</Measure> </div>
</div> </div>
)} )}
</Reference> </Reference>

View file

@ -4,9 +4,9 @@ import React, {
ComponentProps, ComponentProps,
ForwardedRef, ForwardedRef,
forwardRef, forwardRef,
MutableRefObject,
ReactNode, ReactNode,
useEffect, useEffect,
useImperativeHandle,
useRef, useRef,
} from 'react'; } from 'react';
import { ScrollDirection } from 'Helpers/Props/scrollDirections'; import { ScrollDirection } from 'Helpers/Props/scrollDirections';
@ -43,13 +43,14 @@ const Scroller = forwardRef(
...otherProps ...otherProps
} = props; } = props;
const internalRef = useRef(); const internalRef = useRef<HTMLDivElement>(null);
const currentRef = (ref as MutableRefObject<HTMLDivElement>) ?? internalRef;
useImperativeHandle(ref, () => internalRef.current!, []);
useEffect( useEffect(
() => { () => {
if (initialScrollTop != null) { if (initialScrollTop != null) {
currentRef.current.scrollTop = initialScrollTop; internalRef.current!.scrollTop = initialScrollTop;
} }
}, },
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@ -58,16 +59,16 @@ const Scroller = forwardRef(
useEffect(() => { useEffect(() => {
if (scrollTop != null) { if (scrollTop != null) {
currentRef.current.scrollTop = scrollTop; internalRef.current!.scrollTop = scrollTop;
} }
if (autoFocus && scrollDirection !== 'none') { if (autoFocus && scrollDirection !== 'none') {
currentRef.current.focus({ preventScroll: true }); internalRef.current!.focus({ preventScroll: true });
} }
}, [autoFocus, currentRef, scrollDirection, scrollTop]); }, [autoFocus, scrollDirection, scrollTop]);
useEffect(() => { useEffect(() => {
const div = currentRef.current; const div = internalRef.current!;
const handleScroll = throttle(() => { const handleScroll = throttle(() => {
const scrollLeft = div.scrollLeft; const scrollLeft = div.scrollLeft;
@ -76,17 +77,17 @@ const Scroller = forwardRef(
onScroll?.({ scrollLeft, scrollTop }); onScroll?.({ scrollLeft, scrollTop });
}, 10); }, 10);
div.addEventListener('scroll', handleScroll); div?.addEventListener('scroll', handleScroll);
return () => { return () => {
div.removeEventListener('scroll', handleScroll); div?.removeEventListener('scroll', handleScroll);
}; };
}, [currentRef, onScroll]); }, [onScroll]);
return ( return (
<div <div
{...otherProps} {...otherProps}
ref={currentRef} ref={internalRef}
className={classNames( className={classNames(
className, className,
styles.scroller, styles.scroller,