@uiblock/hooks
v1.2.0
Published
A collection of modern, reusable, and production-ready React custom hooks built with TypeScript
Maintainers
Readme
Installation
npm install @uiblock/hooksHooks
Browser APIs
- useIntersectionObserver - Detect when elements enter the viewport
- useResizeObserver - Track element size changes in real-time
- useMutationObserver - Observe DOM mutations and changes
- useGeolocation - Track user position with automatic cleanup
- useMediaQuery - Responsive design with media query detection
- useOnlineStatus - Network detection with offline queue sync
- useCopyToClipboard - Copy to clipboard with fallback support
Performance & Optimization
- useThrottle - Limit function calls for scroll/resize events
- useDebounce - Delay execution for search and form validation
- useEventListener - Prevent memory leaks with auto-cleanup
- useAnimationFrame - Smooth animations and visual updates
- usePrevious - Track previous state/props efficiently
- useDeepCompareEffect - Prevent infinite re-renders with deep comparison
- useConstant - Create stable reference initialized once
Data Fetching & Async
- useFetch - Robust fetching with loading/error states and request cancellation
- useAsync - Generic wrapper for any async function or Promise
- usePoll - Polling API with pause/resume control
- useWebSocket - WebSocket with reconnection logic and message queue
- useQueryParams - Sync URL search params with component state
UI Behaviour
- useScrollLock - Prevent body scroll when modal open
- useOnClickOutside - Close popups/menus/modals reliably
- useKeyPress - Detect key presses and keyboard shortcuts
- useHover - Track hover state with pointer events fallback
- useFocusTrap - Trap focus in modals, dialogs, menus
- usePortal - Create/cleanup DOM nodes for overlays/modals
State Management
- useUndoRedo - Time-travel state with undo/redo functionality
- useGlobalState - Lightweight global state store (Context + Reducer)
- useImmer - Immutable state with drafts (Immer-like)
- useReducerWithEffects - Reducer with side effects for state machines
Quick Examples
Data Fetching
useFetch
import { useFetch } from '@uiblock/hooks'
function UserProfile({ userId }) {
const { data, loading, error } = useFetch(`/api/users/${userId}`)
if (loading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return <div>{data.name}</div>
}useWebSocket
import { useWebSocket } from '@uiblock/hooks'
function Chat() {
const { status, lastMessage, send } = useWebSocket('wss://chat.example.com')
return (
<div>
<div>Status: {status}</div>
<button onClick={() => send('Hello!')}>Send</button>
{lastMessage && <div>{lastMessage.data}</div>}
</div>
)
}Performance
useDebounce
import { useDebounce } from '@uiblock/hooks'
function SearchBox() {
const [search, setSearch] = useState('')
const debouncedSearch = useDebounce(search, 500)
useEffect(() => {
// API call only fires after user stops typing
if (debouncedSearch) {
fetchResults(debouncedSearch)
}
}, [debouncedSearch])
return <input value={search} onChange={e => setSearch(e.target.value)} />
}UI Behaviour
useOnClickOutside
import { useOnClickOutside } from '@uiblock/hooks'
function Dropdown() {
const [isOpen, setIsOpen] = useState(false)
const dropdownRef = useRef(null)
useOnClickOutside(dropdownRef, () => setIsOpen(false))
return (
<div ref={dropdownRef}>
<button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
{isOpen && <div className='dropdown-menu'>Menu items</div>}
</div>
)
}useKeyPress
import { useKeyPress, useKeyboardShortcut } from '@uiblock/hooks'
function Editor() {
const enterPressed = useKeyPress('Enter')
useKeyboardShortcut({ key: 's', meta: true }, () => {
console.log('Save!')
})
return <div>Press Enter or Cmd+S</div>
}Advanced Patterns
useUndoRedo
import { useUndoRedo } from '@uiblock/hooks'
function TextEditor() {
const { state, setState, undo, redo, canUndo, canRedo } = useUndoRedo({
initialState: { text: '' },
maxHistory: 50
})
return (
<div>
<textarea
value={state.text}
onChange={e => setState({ text: e.target.value })}
/>
<button onClick={undo} disabled={!canUndo}>
Undo
</button>
<button onClick={redo} disabled={!canRedo}>
Redo
</button>
</div>
)
}useStableCallback
import { useStableCallback } from '@uiblock/hooks'
function Component() {
const [count, setCount] = useState(0)
// Always uses latest count value, no stale closures!
const logCount = useStableCallback(() => {
console.log(count)
})
useEffect(() => {
const interval = setInterval(logCount, 1000)
return () => clearInterval(interval)
}, [logCount])
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
}useSyncExternalStore
import { useSyncExternalStore, createStore } from '@uiblock/hooks'
// Create a store outside components
const counterStore = createStore({ count: 0 })
function Counter() {
const state = useSyncExternalStore(counterStore)
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => counterStore.setState({ count: state.count + 1 })}>
Increment
</button>
</div>
)
}State Management
useGlobalState
import { createGlobalState } from '@uiblock/hooks'
const { Provider, useGlobalState } = createGlobalState(
(state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 }
default:
return state
}
},
{ count: 0 }
)
function App() {
return (
<Provider>
<Counter />
</Provider>
)
}
function Counter() {
const [state, dispatch] = useGlobalState()
return (
<button onClick={() => dispatch({ type: 'INCREMENT' })}>
Count: {state.count}
</button>
)
}useImmer
import { useImmer } from '@uiblock/hooks'
function TodoList() {
const [state, updateState] = useImmer({ todos: [] })
const addTodo = text => {
// Write "mutating" code that produces immutable updates
updateState(draft => {
draft.todos.push({ id: Date.now(), text, completed: false })
})
}
const toggleTodo = id => {
updateState(draft => {
const todo = draft.todos.find(t => t.id === id)
if (todo) {
todo.completed = !todo.completed
}
})
}
return <div>{/* UI */}</div>
}Routing
useQueryParams
import { useQueryParams } from '@uiblock/hooks'
function ProductList() {
const { params, setParam } = useQueryParams({
search: '',
page: 1,
sort: 'name'
})
return (
<div>
<input
value={params.search}
onChange={e => setParam('search', e.target.value)}
/>
<div>Page: {params.page}</div>
</div>
)
}Documentation
For detailed documentation and live demos, visit: https://hooks.uiblock.in/
Features
- ✅ TypeScript - Full type safety and IntelliSense support
- ✅ Tree-shakeable - Import only what you need
- ✅ SSR Compatible - Works with Next.js and other SSR frameworks
- ✅ Well Tested - Comprehensive test coverage
- ✅ Zero Dependencies - Only peer dependency on React
- ✅ Production Ready - Used in real-world applications
Requirements
- React 18.0.0 or higher
License
MIT © Gulshan Jangra
