Utility Hooks
Common utility Hooks
useLocalStorage
React wrapper for localStorage.
import { useLocalStorage } from '@linch-tech/desktop-core';
function Counter() {
const [count, setCount] = useLocalStorage('counter', 0);
return (
<button onClick={() => setCount(count + 1)}>
Click count: {count}
</button>
);
}Signature
function useLocalStorage<T>(
key: string,
initialValue: T
): [T, (value: T | ((val: T) => T)) => void]useAsync
Async operation state management.
import { useAsync } from '@linch-tech/desktop-core';
function UserProfile({ userId }: { userId: string }) {
const { data, loading, error, execute } = useAsync(
() => fetchUser(userId),
[userId]
);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!data) return null;
return <div>{data.name}</div>;
}Return Value
interface UseAsyncReturn<T> {
data: T | null;
loading: boolean;
error: Error | null;
execute: () => Promise<T>;
}useFetch
HTTP request wrapper.
import { useFetch } from '@linch-tech/desktop-core';
function UserList() {
const { data, loading, error } = useFetch<User[]>('/api/users');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data?.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}useDebounce
Value debouncing.
import { useDebounce } from '@linch-tech/desktop-core';
function SearchInput() {
const [value, setValue] = useState('');
const debouncedValue = useDebounce(value, 300);
useEffect(() => {
// Only triggers when user stops typing for 300ms
searchApi(debouncedValue);
}, [debouncedValue]);
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Search..."
/>
);
}useDebouncedCallback
Callback debouncing.
import { useDebouncedCallback } from '@linch-tech/desktop-core';
function Editor() {
const saveToServer = useDebouncedCallback(
(content: string) => {
api.save(content);
},
500
);
return (
<textarea onChange={(e) => saveToServer(e.target.value)} />
);
}useThrottle
Value throttling.
import { useThrottle } from '@linch-tech/desktop-core';
function ScrollPosition() {
const [scrollY, setScrollY] = useState(0);
const throttledScrollY = useThrottle(scrollY, 100);
useEffect(() => {
const handleScroll = () => setScrollY(window.scrollY);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return <div>Scroll position: {throttledScrollY}</div>;
}useThrottledCallback
Callback throttling.
import { useThrottledCallback } from '@linch-tech/desktop-core';
function MouseTracker() {
const handleMouseMove = useThrottledCallback(
(e: MouseEvent) => {
console.log(e.clientX, e.clientY);
},
100
);
useEffect(() => {
window.addEventListener('mousemove', handleMouseMove);
return () => window.removeEventListener('mousemove', handleMouseMove);
}, [handleMouseMove]);
return null;
}useClickOutside
Click outside detection.
import { useRef } from 'react';
import { useClickOutside } from '@linch-tech/desktop-core';
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useClickOutside(ref, () => {
setIsOpen(false);
});
return (
<div ref={ref}>
<button onClick={() => setIsOpen(true)}>Open</button>
{isOpen && <div className="dropdown-menu">Menu content</div>}
</div>
);
}useClickOutsideMultiple
Multiple elements click outside detection.
import { useClickOutsideMultiple } from '@linch-tech/desktop-core';
function ComplexDropdown() {
const triggerRef = useRef<HTMLButtonElement>(null);
const menuRef = useRef<HTMLDivElement>(null);
useClickOutsideMultiple([triggerRef, menuRef], () => {
setIsOpen(false);
});
return (
<>
<button ref={triggerRef}>Trigger</button>
<div ref={menuRef}>Menu</div>
</>
);
}useEscapeKey
ESC key detection.
import { useEscapeKey } from '@linch-tech/desktop-core';
function Modal({ onClose }: { onClose: () => void }) {
useEscapeKey(onClose);
return (
<div className="modal">
<p>Press ESC to close</p>
</div>
);
}useClickOutsideOrEscape
Combined: click outside or press ESC to close.
import { useClickOutsideOrEscape } from '@linch-tech/desktop-core';
function Popover() {
const [isOpen, setIsOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useClickOutsideOrEscape(ref, () => setIsOpen(false));
return (
<div ref={ref}>
{isOpen && <div>Click outside or press ESC to close</div>}
</div>
);
}