Skip to content

Commit

Permalink
feat(refactor): Generalise useSize hook (#2312)
Browse files Browse the repository at this point in the history
  • Loading branch information
rossbulat authored Nov 2, 2024
1 parent fa4df58 commit 51ec08a
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 33 deletions.
4 changes: 3 additions & 1 deletion src/canvas/JoinPool/Overview/PerformanceGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { formatSize } from 'library/Graphs/Utils';
import { useSize } from 'hooks/useSize';
import type { OverviewSectionProps } from '../types';
import { useTranslation } from 'react-i18next';
import { useUi } from 'contexts/UI';

ChartJS.register(
CategoryScale,
Expand All @@ -47,6 +48,7 @@ export const PerformanceGraph = ({
const { t } = useTranslation();
const { mode } = useTheme();
const { openHelp } = useHelp();
const { containerRefs } = useUi();
const { colors } = useNetwork().networkData;
const { getPoolRewardPoints } = usePoolPerformance();

Expand All @@ -57,7 +59,7 @@ export const PerformanceGraph = ({
const graphInnerRef = useRef<HTMLDivElement>(null);

// Get the size of the graph container.
const size = useSize(graphInnerRef?.current || undefined);
const size = useSize(graphInnerRef, containerRefs?.mainInterface);
const { width, height } = formatSize(size, 150);

// Format reward points as an array of strings, or an empty array if syncing.
Expand Down
8 changes: 5 additions & 3 deletions src/contexts/UI/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only

import { localStorageOrDefault, setStateWithRef } from '@w3ux/utils';
import type { ReactNode, RefObject } from 'react';
import type { MutableRefObject, ReactNode } from 'react';
import { createContext, useContext, useEffect, useRef, useState } from 'react';
import { PageWidthMediumThreshold } from 'consts';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
Expand All @@ -25,9 +25,11 @@ export const UIProvider = ({ children }: { children: ReactNode }) => {

// Store references for main app containers.
const [containerRefs, setContainerRefsState] = useState<
Record<string, RefObject<HTMLDivElement>>
Record<string, MutableRefObject<HTMLDivElement | null>>
>({});
const setContainerRefs = (v: Record<string, RefObject<HTMLDivElement>>) => {
const setContainerRefs = (
v: Record<string, MutableRefObject<HTMLDivElement | null>>
) => {
setContainerRefsState(v);
};

Expand Down
8 changes: 5 additions & 3 deletions src/contexts/UI/types.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import type { RefObject } from 'react';
import type { MutableRefObject } from 'react';

export interface UIContextInterface {
setSideMenu: (v: boolean) => void;
setUserSideMenuMinimised: (v: boolean) => void;
setContainerRefs: (v: Record<string, RefObject<HTMLDivElement>>) => void;
setContainerRefs: (
v: Record<string, MutableRefObject<HTMLDivElement | null>>
) => void;
sideMenuOpen: boolean;
userSideMenuMinimised: boolean;
sideMenuMinimised: boolean;
containerRefs: Record<string, RefObject<HTMLDivElement>>;
containerRefs: Record<string, MutableRefObject<HTMLDivElement | null>>;
isBraveBrowser: boolean;
}
51 changes: 30 additions & 21 deletions src/hooks/useSize/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,47 @@
// SPDX-License-Identifier: GPL-3.0-only

import throttle from 'lodash.throttle';
import type { MutableRefObject } from 'react';
import { useEffect, useState } from 'react';
import { useUi } from 'contexts/UI';

export const getSize = (element?: HTMLElement | undefined) => {
const width = element?.offsetWidth || 0;
const height = element?.offsetHeight || 0;
return { height, width };
};
// Custom hook to get the width and height of a specified element. Updates the `size` state when the
// specified "outer element" (or the window by default) resizes.
export const useSize = (
element: MutableRefObject<HTMLElement | null | undefined>,
outerElement?: MutableRefObject<HTMLElement | null | undefined>
) => {
// Helper function to retrieve the width and height of an element
// If no element is found, default dimensions are set to 0.
const getSize = (el: HTMLElement | null = null) => {
const width = el?.offsetWidth || 0;
const height = el?.offsetHeight || 0;
return { width, height };
};

export const useSize = (element?: HTMLElement | undefined) => {
const { containerRefs } = useUi();
// State to store the current width and height of the specified element.
const [size, setSize] = useState<{ width: number; height: number }>(
getSize(element)
getSize(element?.current)
);

const throttleCallback = () => {
setSize(getSize(element));
};
// Throttle the resize event handler to limit how often size updates occur.
const resizeThrottle = throttle(() => {
setSize(getSize(element?.current));
}, 100);

// Set up the resize event listener on mount and clean it up on unmount.
useEffect(() => {
const resizeThrottle = throttle(throttleCallback, 100, {
trailing: true,
leading: false,
});

// listen to main interface resize if ref is available, otherwise
// fall back to window resize.
const listenFor = containerRefs?.mainInterface?.current ?? window;
// Determine the target for the resize event listener.
// If `outerElement` is provided, listen to its resize events; otherwise, listen to the window's.
const listenFor = outerElement?.current || window;

listenFor.addEventListener('resize', resizeThrottle);

// Clean up event listener when the component unmounts to avoid memory leaks.
return () => {
listenFor.removeEventListener('resize', resizeThrottle);
};
});
}, [outerElement]);

// Return the current size of the element.
return size;
};
7 changes: 5 additions & 2 deletions src/modals/ValidatorGeo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ import { usePlugins } from 'contexts/Plugins';
import { useNetwork } from 'contexts/Network';
import { PolkaWatchController } from 'controllers/PolkaWatch';
import { ButtonHelp } from 'kits/Buttons/ButtonHelp';
import { useUi } from 'contexts/UI';

export const ValidatorGeo = () => {
const { t } = useTranslation('modals');
const { openHelp } = useHelp();
const { network } = useNetwork();
const { containerRefs } = useUi();
const { options } = useOverlay().modal.config;
const { address, identity } = options;
const { openHelp } = useHelp();

const ref = useRef<HTMLDivElement>(null);
const size = useSize(ref?.current || undefined);
const size = useSize(ref, containerRefs?.mainInterface);
const { height, minHeight } = formatSize(size, 300);

const [pwData, setPwData] = useState<ValidatorDetail>({} as ValidatorDetail);
const [analyticsAvailable, setAnalyticsAvailable] = useState<boolean>(true);
const { pluginEnabled } = usePlugins();
Expand Down
4 changes: 3 additions & 1 deletion src/modals/ValidatorMetrics/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useApi } from 'contexts/Api';
import { ButtonHelp } from 'kits/Buttons/ButtonHelp';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { planckToUnitBn } from 'library/Utils';
import { useUi } from 'contexts/UI';

export const ValidatorMetrics = () => {
const { t } = useTranslation('modals');
Expand All @@ -34,6 +35,7 @@ export const ValidatorMetrics = () => {
} = useNetwork();
const { activeEra } = useApi();
const { plugins } = usePlugins();
const { containerRefs } = useUi();
const { options } = useOverlay().modal.config;
const { address, identity } = options;
const {
Expand All @@ -59,7 +61,7 @@ export const ValidatorMetrics = () => {
const [list, setList] = useState<AnyJson[]>([]);

const ref = useRef<HTMLDivElement>(null);
const size = useSize(ref?.current || undefined);
const size = useSize(ref, containerRefs?.mainInterface);
const { width, height, minHeight } = formatSize(size, 300);

const handleEraPoints = async () => {
Expand Down
4 changes: 3 additions & 1 deletion src/pages/Overview/Payouts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { minDecimalPlaces } from '@w3ux/utils';
import { useNetwork } from 'contexts/Network';
import { useSyncing } from 'hooks/useSyncing';
import { planckToUnitBn } from 'library/Utils';
import { useUi } from 'contexts/UI';

export const Payouts = () => {
const { i18n, t } = useTranslation('pages');
Expand All @@ -33,6 +34,7 @@ export const Payouts = () => {
const { inSetup } = useStaking();
const { syncing } = useSyncing();
const { plugins } = usePlugins();
const { containerRefs } = useUi();
const { getData, injectBlockTimestamp } = useSubscanData([
'payouts',
'unclaimedPayouts',
Expand All @@ -50,7 +52,7 @@ export const Payouts = () => {
const graphInnerRef = useRef<HTMLDivElement>(null);

// Get the size of the graph container.
const size = useSize(graphInnerRef?.current || undefined);
const size = useSize(graphInnerRef, containerRefs?.mainInterface);
const { width, height, minHeight } = formatSize(size, 260);

// Get the last reward with its timestmap.
Expand Down
4 changes: 3 additions & 1 deletion src/pages/Payouts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ import { DefaultLocale, locales } from 'locale';
import { useSyncing } from 'hooks/useSyncing';
import { ButtonHelp } from 'kits/Buttons/ButtonHelp';
import { PageTitle } from 'kits/Structure/PageTitle';
import { useUi } from 'contexts/UI';

export const Payouts = ({ page: { key } }: PageProps) => {
const { i18n, t } = useTranslation();
const { openHelp } = useHelp();
const { plugins } = usePlugins();
const { inSetup } = useStaking();
const { syncing } = useSyncing();
const { containerRefs } = useUi();
const { getData, injectBlockTimestamp } = useSubscanData([
'payouts',
'unclaimedPayouts',
Expand All @@ -43,7 +45,7 @@ export const Payouts = ({ page: { key } }: PageProps) => {
const [payoutsList, setPayoutLists] = useState<AnySubscan>([]);

const ref = useRef<HTMLDivElement>(null);
const size = useSize(ref?.current || undefined);
const size = useSize(ref, containerRefs?.mainInterface);
const { width, height, minHeight } = formatSize(size, 280);

// Get data safely from subscan hook.
Expand Down

0 comments on commit 51ec08a

Please sign in to comment.