From 487c832f5b5f8c089e6f2701142c2c46eeda67b3 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Tue, 10 Jan 2023 20:04:47 +0100 Subject: [PATCH] Improved types on element ref objects and their usage --- src/domains/helpers/DomainStatusIcon.tsx | 10 +++++----- src/servers/helpers/ImportServersBtn.tsx | 9 ++++----- src/short-urls/helpers/ShortUrlStatus.tsx | 10 +++++----- src/short-urls/helpers/ShortUrlVisitsCount.tsx | 9 ++++----- src/utils/InfoTooltip.tsx | 10 +++++----- src/utils/helpers/components.ts | 5 ----- src/utils/helpers/hooks.ts | 4 +++- 7 files changed, 26 insertions(+), 31 deletions(-) delete mode 100644 src/utils/helpers/components.ts diff --git a/src/domains/helpers/DomainStatusIcon.tsx b/src/domains/helpers/DomainStatusIcon.tsx index 79fe86ea..7a1e6ded 100644 --- a/src/domains/helpers/DomainStatusIcon.tsx +++ b/src/domains/helpers/DomainStatusIcon.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect, useRef, useState } from 'react'; +import { FC, useEffect, useState } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; import { ExternalLink } from 'react-external-link'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -8,8 +8,8 @@ import { faCircleNotch as loadingStatusIcon, } from '@fortawesome/free-solid-svg-icons'; import { MediaMatcher } from '../../utils/types'; -import { mutableRefToElementRef } from '../../utils/helpers/components'; import { DomainStatus } from '../data'; +import { useElementRef } from '../../utils/helpers/hooks'; interface DomainStatusIconProps { status: DomainStatus; @@ -17,7 +17,7 @@ interface DomainStatusIconProps { } export const DomainStatusIcon: FC = ({ status, matchMedia = window.matchMedia }) => { - const ref = useRef(); + const ref = useElementRef(); const matchesMobile = () => matchMedia('(max-width: 991px)').matches; const [isMobile, setIsMobile] = useState(matchesMobile()); @@ -35,13 +35,13 @@ export const DomainStatusIcon: FC = ({ status, matchMedia return ( <> - + {status === 'valid' ? : } ref.current) as any} + target={ref} placement={isMobile ? 'top-start' : 'left'} autohide={status === 'valid'} > diff --git a/src/servers/helpers/ImportServersBtn.tsx b/src/servers/helpers/ImportServersBtn.tsx index 7df560ac..4ce8502a 100644 --- a/src/servers/helpers/ImportServersBtn.tsx +++ b/src/servers/helpers/ImportServersBtn.tsx @@ -1,10 +1,9 @@ -import { useRef, ChangeEvent, useState, useEffect, FC, PropsWithChildren } from 'react'; +import { ChangeEvent, useState, useEffect, FC, PropsWithChildren } from 'react'; import { Button, UncontrolledTooltip } from 'reactstrap'; import { complement, pipe } from 'ramda'; import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useToggle } from '../../utils/helpers/hooks'; -import { mutableRefToElementRef } from '../../utils/helpers/components'; +import { useElementRef, useToggle } from '../../utils/helpers/hooks'; import { ServersImporter } from '../services/ServersImporter'; import { ServerData, ServersMap } from '../data'; import { DuplicatedServersModal } from './DuplicatedServersModal'; @@ -34,7 +33,7 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC tooltipPlacement = 'bottom', className = '', }) => { - const ref = useRef(); + const ref = useElementRef(); const [serversToCreate, setServersToCreate] = useState(); const [duplicatedServers, setDuplicatedServers] = useState([]); const [isModalOpen,, showModal, hideModal] = useToggle(); @@ -79,7 +78,7 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC type="file" accept="text/csv" className="import-servers-btn__csv-select" - ref={mutableRefToElementRef(ref)} + ref={ref} onChange={onFile} /> diff --git a/src/short-urls/helpers/ShortUrlStatus.tsx b/src/short-urls/helpers/ShortUrlStatus.tsx index 7fcc2a6d..0803e658 100644 --- a/src/short-urls/helpers/ShortUrlStatus.tsx +++ b/src/short-urls/helpers/ShortUrlStatus.tsx @@ -1,12 +1,12 @@ -import { FC, ReactNode, useRef } from 'react'; +import { FC, ReactNode } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IconDefinition } from '@fortawesome/fontawesome-common-types'; import { faLinkSlash, faCalendarXmark, faCheck } from '@fortawesome/free-solid-svg-icons'; import { UncontrolledTooltip } from 'reactstrap'; import { isBefore } from 'date-fns'; -import { mutableRefToElementRef } from '../../utils/helpers/components'; import { ShortUrl } from '../data'; import { formatHumanFriendly, now, parseISO } from '../../utils/helpers/date'; +import { useElementRef } from '../../utils/helpers/hooks'; interface ShortUrlStatusProps { shortUrl: ShortUrl; @@ -70,15 +70,15 @@ const resolveShortUrlStatus = (shortUrl: ShortUrl): StatusResult => { }; export const ShortUrlStatus: FC = ({ shortUrl }) => { - const tooltipRef = useRef(); + const tooltipRef = useElementRef(); const { icon, className, description } = resolveShortUrlStatus(shortUrl); return ( <> - + - tooltipRef.current) as any} placement="bottom"> + {description} diff --git a/src/short-urls/helpers/ShortUrlVisitsCount.tsx b/src/short-urls/helpers/ShortUrlVisitsCount.tsx index dfa0acf3..b73cc595 100644 --- a/src/short-urls/helpers/ShortUrlVisitsCount.tsx +++ b/src/short-urls/helpers/ShortUrlVisitsCount.tsx @@ -1,4 +1,3 @@ -import { useRef } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { UncontrolledTooltip } from 'reactstrap'; @@ -7,8 +6,8 @@ import { prettify } from '../../utils/helpers/numbers'; import { ShortUrl } from '../data'; import { SelectedServer } from '../../servers/data'; import { ShortUrlDetailLink } from './ShortUrlDetailLink'; -import { mutableRefToElementRef } from '../../utils/helpers/components'; import { formatHumanFriendly, parseISO } from '../../utils/helpers/date'; +import { useElementRef } from '../../utils/helpers/hooks'; import './ShortUrlVisitsCount.scss'; interface ShortUrlVisitsCountProps { @@ -37,20 +36,20 @@ export const ShortUrlVisitsCount = ( return visitsLink; } - const tooltipRef = useRef(); + const tooltipRef = useElementRef(); return ( <> {visitsLink} - + {maxVisits && <> / {prettify(maxVisits)}} - tooltipRef.current) as any} placement="bottom"> +
    {maxVisits && (
  • diff --git a/src/utils/InfoTooltip.tsx b/src/utils/InfoTooltip.tsx index 15ecae62..9d2eaa28 100644 --- a/src/utils/InfoTooltip.tsx +++ b/src/utils/InfoTooltip.tsx @@ -1,9 +1,9 @@ -import { FC, PropsWithChildren, useRef } from 'react'; +import { FC, PropsWithChildren } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { UncontrolledTooltip } from 'reactstrap'; import { Placement } from '@popperjs/core'; -import { mutableRefToElementRef } from './helpers/components'; +import { useElementRef } from './helpers/hooks'; export type InfoTooltipProps = PropsWithChildren<{ className?: string; @@ -11,14 +11,14 @@ export type InfoTooltipProps = PropsWithChildren<{ }>; export const InfoTooltip: FC = ({ className = '', placement, children }) => { - const ref = useRef(); + const ref = useElementRef(); return ( <> - + - ref.current) as any} placement={placement}>{children} + {children} ); }; diff --git a/src/utils/helpers/components.ts b/src/utils/helpers/components.ts deleted file mode 100644 index 0abe4bbc..00000000 --- a/src/utils/helpers/components.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { MutableRefObject, Ref } from 'react'; - -export const mutableRefToElementRef = (ref: MutableRefObject): Ref => (el) => { - ref.current = el ?? undefined; // eslint-disable-line no-param-reassign -}; diff --git a/src/utils/helpers/hooks.ts b/src/utils/helpers/hooks.ts index 56406afa..fc596ddb 100644 --- a/src/utils/helpers/hooks.ts +++ b/src/utils/helpers/hooks.ts @@ -1,4 +1,4 @@ -import { useState, useRef, EffectCallback, DependencyList, useEffect } from 'react'; +import { DependencyList, EffectCallback, useEffect, useRef, useState } from 'react'; import { useSwipeable as useReactSwipeable } from 'react-swipeable'; import { useLocation, useNavigate } from 'react-router-dom'; import { v4 as uuid } from 'uuid'; @@ -91,3 +91,5 @@ export const useDomId = (): string => { const { current: id } = useRef(`dom-${uuid()}`); return id; }; + +export const useElementRef = () => useRef(null);