Skip to content

Commit

Permalink
refactor(hooks): Combine debounced hooks into single hook.
Browse files Browse the repository at this point in the history
- Combine useDebouncedResize and useDebouncedScroll into useDebouncedEvent.
- Support mousedown events now.
- Update other hooks to use useDebouncedEvent.
  • Loading branch information
ZL-Asica committed Nov 14, 2024
1 parent 202ae94 commit 8621dbb
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 58 deletions.
3 changes: 1 addition & 2 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export { default as useDebouncedResize } from './useDebouncedResize';
export { default as useDebouncedScroll } from './useDebouncedScroll';
export { default as useDebouncedEvent } from './useDebouncedEvent';
export { default as useOutsideClick } from './useOutsideClick';
export { default as useScrollProgress } from './useScrollProgress';
export { default as useVisibilityOnScroll } from './useVisibilityOnScroll';
Expand Down
37 changes: 37 additions & 0 deletions src/hooks/useDebouncedEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useEffect } from 'react';
import { debounce } from 'es-toolkit/compat';

interface UseDebouncedEventOptions {
events?: Array<'resize' | 'scroll' | 'mousedown'>;
delay?: number;
}

const useDebouncedEvent = <T extends Event>(
callback: (event: T) => void,
{ events = ['scroll'], delay = 100 }: UseDebouncedEventOptions
) => {
useEffect(() => {
if (typeof globalThis === 'undefined') return; // Skip in SSR

// Use a debounced callback
const debouncedCallback = debounce(
(event: Event) => callback(event as T),
delay
);

// Add event listeners
for (const event of events)
globalThis.addEventListener(event, debouncedCallback as EventListener);

// Remove event listeners
return () => {
for (const event of events)
globalThis.removeEventListener(
event,
debouncedCallback as EventListener
);
};
}, [callback, events, delay]);
};

export default useDebouncedEvent;
16 changes: 0 additions & 16 deletions src/hooks/useDebouncedResize.ts

This file was deleted.

16 changes: 0 additions & 16 deletions src/hooks/useDebouncedScroll.ts

This file was deleted.

27 changes: 10 additions & 17 deletions src/hooks/useOutsideClick.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
import { useEffect } from 'react';
import { debounce } from 'es-toolkit/compat';
import { useDebouncedEvent } from '@/hooks';

const useOutsideClick = (
reference: React.RefObject<HTMLElement | null>,
callback: () => void
) => {
useEffect(() => {
const handleClickOutside = debounce((event: MouseEvent) => {
if (
reference.current &&
!reference.current.contains(event.target as Node)
) {
callback();
}
}, 100); // 100ms debounce delay for click
const handleClickOutside = (event: MouseEvent) => {
if (
reference.current &&
!reference.current.contains(event.target as Node)
) {
callback();
}
};

document.addEventListener('mousedown', handleClickOutside);
return () => {
handleClickOutside.cancel();
document.removeEventListener('mousedown', handleClickOutside);
};
}, [reference, callback]);
useDebouncedEvent(handleClickOutside, { events: ['mousedown'] });
};

export default useOutsideClick;
4 changes: 2 additions & 2 deletions src/hooks/useScrollProgress.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';

import useDebouncedScroll from '@/hooks/useDebouncedScroll';
import { useDebouncedEvent } from '@/hooks';

const useScrollProgress = () => {
const [scrollProgress, setScrollProgress] = useState(0);
Expand All @@ -15,7 +15,7 @@ const useScrollProgress = () => {
updateScrollProgress();
}, []);

useDebouncedScroll(() => requestAnimationFrame(updateScrollProgress));
useDebouncedEvent(() => requestAnimationFrame(updateScrollProgress), {});

return scrollProgress;
};
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useTOCLogic.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useRef, useEffect } from 'react';
import { useRouter } from 'next/navigation';

import { useDebouncedResize, useOutsideClick } from '@/hooks';
import { useDebouncedEvent, useOutsideClick } from '@/hooks';

function useTOCLogic(onLinkClick?: (slug: string) => void) {
const [activeSlug, setActiveSlug] = useState('');
Expand Down Expand Up @@ -40,7 +40,7 @@ function useTOCLogic(onLinkClick?: (slug: string) => void) {
};

// Update activeSlug on scroll
useDebouncedResize(updateActiveSlug, { delay: 20 });
useDebouncedEvent(updateActiveSlug, { delay: 20 });

// Close TOC when clicking outside
useOutsideClick(tocReference, () => {
Expand Down
6 changes: 3 additions & 3 deletions src/hooks/useVisibilityOnScroll.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useEffect, useState } from 'react';

import useDebouncedScroll from '@/hooks/useDebouncedScroll';
import useDebouncedEvent from '@/hooks/useDebouncedEvent';

const useVisibilityOnScroll = (threshold: number = 100) => {
const useVisibilityOnScroll = (threshold: number = 150) => {
const [isVisible, setIsVisible] = useState(false);
const [isAtBottom, setIsAtBottom] = useState(false);

Expand All @@ -23,7 +23,7 @@ const useVisibilityOnScroll = (threshold: number = 100) => {
updateVisibility();
}, []);

useDebouncedScroll(updateVisibility);
useDebouncedEvent(updateVisibility, {});

return { isVisible, isAtBottom };
};
Expand Down

0 comments on commit 8621dbb

Please sign in to comment.