Return

All tests / src/hooks useWindowResize.ts

82.6% Statements 19/23
46.15% Branches 6/13
83.33% Functions 5/6
90% Lines 18/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 831x 1x                       6x                                       6x 3x   3x 3x 3x               3x 3x                   3x         3x   3x   3x 3x 3x       6x                 6x  
import React from 'react';
import { mobileMax, tabletMax, tabletMin, desktopMin } from '@/constants/devices';
 
type WindowTpe = {
    isMobile: boolean;
    isTablet: boolean;
    isMobileOrTablet: boolean;
    isDesktop: boolean;
    width: number;
    height: number;
};
 
function useWindowResize(): WindowTpe {
    const [widowSize, setWindowSize] = React.useState({
        isMobile: false,
        isTablet: false,
        isDesktop: false,
        width: 0,
        height: 0,
    });
 
    /**
     * SDD-L09-T11. `handleResize` used to read `window.innerWidth` four times and `innerHeight`
     * once, then call `setWindowSize` with a **new object** — on every single resize event. A drag
     * of a desktop window fires those by the hundred, and each one produced a state object that was
     * never equal to the last by identity, so every one re-rendered the whole subtree. On the survey
     * page that subtree includes a full-viewport `<Confetti>` canvas.
     *
     * Two changes. The measurement is now coalesced into one animation frame, which is the rate at
     * which a change could be painted anyway; and the result is compared field by field, so the
     * common case — a resize that does not cross a breakpoint and does not change the numbers React
     * renders — bails out without touching state at all.
     */
    React.useEffect(() => {
        let frame = 0;
 
        const measure = () => {
            frame = 0;
            const next = {
                isMobile: window.innerWidth <= mobileMax,
                isTablet: window.innerWidth <= tabletMax && window.innerWidth >= tabletMin,
                isDesktop: window.innerWidth >= desktopMin,
                width: window.innerWidth,
                height: window.innerHeight,
            };
 
            setWindowSize((current) =>
                current.width === next.width &&
                current.height === next.height &&
                current.isMobile === next.isMobile &&
                current.isTablet === next.isTablet &&
                current.isDesktop === next.isDesktop
                    ? current
                    : next
            );
        };
 
        const handleResize = () => {
            Iif (frame) return;
            frame = window.requestAnimationFrame(measure);
        };
 
        window.addEventListener('resize', handleResize);
 
        measure();
 
        return () => {
            Iif (frame) window.cancelAnimationFrame(frame);
            window.removeEventListener('resize', handleResize);
        };
    }, []);
 
    return {
        isMobile: widowSize.isMobile,
        isTablet: widowSize.isTablet,
        isMobileOrTablet: widowSize.isMobile || widowSize.isTablet,
        isDesktop: widowSize.isDesktop,
        width: widowSize.width,
        height: widowSize.height,
    };
}
export default useWindowResize;