A collection of lightweight, reusable React hooks for common UI patterns and functionalities.
npm install react-custom-hooks-collection
# or
yarn add react-custom-hooks-collection
# or
pnpm add react-custom-hooks-collection
-
useToggle
- Toggle boolean states -
useForm
- Form state management -
useLocalStorage
- Local storage state management -
useClickOutside
- Detect clicks outside elements -
useMediaQuery
- Responsive media queries -
useDebounce
- Debounce values -
useFetch
- Data fetching with cache -
useKeyPress
- Keyboard event handling -
usePagination
- Pagination logic -
useInfiniteScroll
- Infinite scrolling -
useClipboard
- Clipboard operations -
useHistory
- State history management
Simple boolean state toggle.
import { useToggle } from 'react-custom-hooks-collection';
const ToggleExample = () => {
const [isOn, toggle] = useToggle(false);
return (
<button onClick={toggle}>
{isOn ? 'Turn Off' : 'Turn On'}
</button>
);
};
Form state management with validation.
import { useForm } from 'react-custom-hooks-collection';
const FormExample = () => {
const { values, errors, handleChange, handleSubmit } = useForm({
initialValues: {
email: '',
password: ''
},
validate: (values) => {
const errors: Record<string, string> = {};
if (!values.email) errors.email = 'Required';
if (!values.password) errors.password = 'Required';
return errors;
},
onSubmit: (values) => {
console.log(values);
}
});
return (
<form onSubmit={handleSubmit}>
<input
name="email"
value={values.email}
onChange={handleChange}
/>
{errors.email && <span>{errors.email}</span>}
<input
name="password"
type="password"
value={values.password}
onChange={handleChange}
/>
{errors.password && <span>{errors.password}</span>}
<button type="submit">Submit</button>
</form>
);
};
Persist state in localStorage.
import { useLocalStorage } from 'react-custom-hooks-collection';
const LocalStorageExample = () => {
const [user, setUser] = useLocalStorage('user', null);
return (
<div>
<button onClick={() => setUser({ name: 'John' })}>
Set User
</button>
<p>User: {JSON.stringify(user)}</p>
</div>
);
};
Detect clicks outside an element.
import { useClickOutside } from 'react-custom-hooks-collection';
const ModalExample = () => {
const [isOpen, setIsOpen] = useState(false);
const modalRef = useClickOutside(() => setIsOpen(false));
return (
<>
<button onClick={() => setIsOpen(true)}>Open Modal</button>
{isOpen && (
<div ref={modalRef}>
Modal Content
</div>
)}
</>
);
};
Responsive design with media queries.
import { useMediaQuery } from 'react-custom-hooks-collection';
const ResponsiveExample = () => {
const isMobile = useMediaQuery('(max-width: 768px)');
const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
return (
<div>
{isMobile && <MobileLayout />}
{isTablet && <TabletLayout />}
{!isMobile && !isTablet && <DesktopLayout />}
</div>
);
};
Debounce rapidly changing values.
import { useDebounce } from 'react-custom-hooks-collection';
const SearchExample = () => {
const [search, setSearch] = useState('');
const debouncedSearch = useDebounce(search, 500);
useEffect(() => {
// API call with debouncedSearch
}, [debouncedSearch]);
return (
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Search..."
/>
);
};
Data fetching with caching.
import { useFetch } from 'react-custom-hooks-collection';
const DataFetchingExample = () => {
const { data, error, loading, refetch } = useFetch<User[]>('/api/users');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<button onClick={refetch}>Refresh</button>
{data?.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
};
Keyboard event handling.
import { useKeyPress } from 'react-custom-hooks-collection';
const ShortcutExample = () => {
useKeyPress('Escape', () => {
console.log('Escape pressed');
});
useKeyPress('Enter', () => {
console.log('Enter pressed');
});
return <div>Press Escape or Enter</div>;
};
Pagination logic.
import { usePagination } from 'react-custom-hooks-collection';
const PaginationExample = () => {
const {
currentPage,
totalPages,
nextPage,
prevPage,
setPage,
currentItems
} = usePagination(items, 10);
return (
<div>
{currentItems.map(item => (
<div key={item.id}>{item.name}</div>
))}
<div>
<button onClick={prevPage}>Previous</button>
<span>Page {currentPage} of {totalPages}</span>
<button onClick={nextPage}>Next</button>
</div>
</div>
);
};
Infinite scrolling functionality.
import { useInfiniteScroll } from 'react-custom-hooks-collection';
const InfiniteListExample = () => {
const [items, setItems] = useState<Item[]>([]);
const isFetching = useInfiniteScroll(loadMore);
async function loadMore() {
const newItems = await fetchMoreItems();
setItems(prev => [...prev, ...newItems]);
}
return (
<div>
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
{isFetching && <div>Loading more...</div>}
</div>
);
};
Clipboard operations.
import { useClipboard } from 'react-custom-hooks-collection';
const ClipboardExample = () => {
const { copy, paste, copiedText, error } = useClipboard();
return (
<div>
<button onClick={() => copy('Hello, World!')}>
Copy Text
</button>
<button onClick={async () => {
const text = await paste();
console.log('Pasted:', text);
}}>
Paste
</button>
{copiedText && <div>Copied: {copiedText}</div>}
{error && <div>Error: {error.message}</div>}
</div>
);
};
State history with undo/redo.
import { useHistory } from 'react-custom-hooks-collection';
const EditorExample = () => {
const [content, setContent, undo, redo] = useHistory('');
return (
<div>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
/>
<button onClick={undo}>Undo</button>
<button onClick={redo}>Redo</button>
</div>
);
};
All hooks are written in TypeScript and include comprehensive type definitions.
Contributions are welcome! Please read our contributing guide for details on our code of conduct, and the process for submitting pull requests.
MIT © [Your Name]
If you find this package helpful, please ⭐️ it on GitHub.