mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Add brewery discovery & detail pages with location-based search (#253)
This commit is contained in:
20
web/frontend/app/hooks/useDebouncedValue.ts
Normal file
20
web/frontend/app/hooks/useDebouncedValue.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
/**
|
||||
* Returns a value that only updates after `delayMs` has passed without `value` changing.
|
||||
*
|
||||
* @example
|
||||
* const debouncedQuery = useDebouncedValue(query, 300);
|
||||
*/
|
||||
const useDebouncedValue = <T>(value: T, delayMs: number): T => {
|
||||
const [debounced, setDebounced] = useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => setDebounced(value), delayMs);
|
||||
return () => clearTimeout(timeout);
|
||||
}, [value, delayMs]);
|
||||
|
||||
return debounced;
|
||||
};
|
||||
|
||||
export default useDebouncedValue;
|
||||
22
web/frontend/app/hooks/useMediaQuery.ts
Normal file
22
web/frontend/app/hooks/useMediaQuery.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useSyncExternalStore } from 'react';
|
||||
|
||||
const subscribe = (query: string) => (callback: () => void) => {
|
||||
const media = window.matchMedia(query);
|
||||
media.addEventListener('change', callback);
|
||||
return () => media.removeEventListener('change', callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracks whether a CSS media query currently matches the viewport, updating on change.
|
||||
*
|
||||
* @example
|
||||
* const isSmallScreen = useMediaQuery('(max-width: 640px)');
|
||||
*/
|
||||
const useMediaQuery = (query: `(${string})`) =>
|
||||
useSyncExternalStore(
|
||||
subscribe(query),
|
||||
() => window.matchMedia(query).matches,
|
||||
() => false,
|
||||
);
|
||||
|
||||
export default useMediaQuery;
|
||||
Reference in New Issue
Block a user