@cocrepo/hooks
v1.3.7
Published
Shared React hooks library
Downloads
149
Readme
@cocrepo/hooks
Shared React hooks library for the Cocrepo monorepo.
Overview
@cocrepo/hooks provides a collection of reusable React hooks for common patterns like data fetching, state management, form handling, and MobX integration.
Features
- 🎣 Custom React Hooks - Reusable logic across applications
- 📊 MobX Integration - Hooks for working with MobX stores
- 🔄 Data Fetching - Simplified API integration patterns
- 📝 Form Handling - Form state and validation utilities
- 🎯 Type-Safe - Full TypeScript support
Installation
pnpm add @cocrepo/hooksUsage
Basic Hook Example
import { useBoolean, useDebounce } from '@cocrepo/hooks';
function SearchComponent() {
const [isOpen, { toggle, setTrue, setFalse }] = useBoolean(false);
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);
useEffect(() => {
// Search with debounced value
if (debouncedSearch) {
performSearch(debouncedSearch);
}
}, [debouncedSearch]);
return (
<div>
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<button onClick={toggle}>
{isOpen ? 'Close' : 'Open'}
</button>
</div>
);
}MobX Store Hooks
import { useStore, useObserver } from '@cocrepo/hooks';
import { observer } from 'mobx-react-lite';
const MyComponent = observer(() => {
const store = useStore();
return (
<div>
{store.users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
});Form Hooks
import { useForm, useFormField } from '@cocrepo/hooks';
function LoginForm() {
const form = useForm({
initialValues: {
email: '',
password: ''
},
onSubmit: async (values) => {
await login(values);
}
});
return (
<form onSubmit={form.handleSubmit}>
<input
name="email"
value={form.values.email}
onChange={form.handleChange}
/>
<input
name="password"
type="password"
value={form.values.password}
onChange={form.handleChange}
/>
<button type="submit">Login</button>
</form>
);
}Data Fetching Hooks
import { useAsync, useAsyncFn } from '@cocrepo/hooks';
function UserProfile({ userId }) {
const { data: user, loading, error } = useAsync(
() => fetchUser(userId),
[userId]
);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{user.name}</div>;
}Available Hooks
State Management
useBoolean- Boolean state with helpersuseCounter- Counter with increment/decrementuseToggle- Toggle between valuesusePrevious- Access previous valueuseLocalStorage- Sync state with localStorageuseSessionStorage- Sync state with sessionStorage
Effects & Lifecycle
useDebounce- Debounce value changesuseThrottle- Throttle function callsuseInterval- Declarative intervaluseTimeout- Declarative timeoutuseUpdateEffect- Skip first render effectuseMount- Run effect on mount onlyuseUnmount- Cleanup on unmount
MobX Integration
useStore- Access MobX root storeuseObserver- Observe MobX observablesuseComputed- Computed values from stores
Forms & Validation
useForm- Complete form managementuseFormField- Individual field managementuseValidation- Form validation utilities
Data & Async
useAsync- Async operationsuseAsyncFn- Async function wrapperuseFetch- Simplified fetch wrapper
DOM & Browser
useClickOutside- Detect clicks outside elementuseEventListener- Add event listenersuseMediaQuery- Responsive media queriesuseWindowSize- Window dimensionsuseScroll- Scroll position tracking
Best Practices
- Composition - Combine simple hooks for complex behavior
- Memoization - Use
useMemoanduseCallbackappropriately - Dependencies - Always specify correct dependency arrays
- Cleanup - Return cleanup functions from effects
- Type Safety - Leverage TypeScript for better DX
Example: Complex Hook Composition
import {
useBoolean,
useDebounce,
useAsync,
useLocalStorage
} from '@cocrepo/hooks';
function useSearchWithHistory(searchFn) {
const [query, setQuery] = useLocalStorage('search-query', '');
const [isSearching, { setTrue, setFalse }] = useBoolean(false);
const debouncedQuery = useDebounce(query, 300);
const { data: results, error } = useAsync(async () => {
if (!debouncedQuery) return [];
setTrue();
try {
return await searchFn(debouncedQuery);
} finally {
setFalse();
}
}, [debouncedQuery]);
return {
query,
setQuery,
results,
isSearching,
error
};
}Testing
# Run tests
pnpm test
# Watch mode
pnpm test:watchTypeScript Support
All hooks are fully typed:
import type { UseFormReturn, UseBooleanReturn } from '@cocrepo/hooks';
const form: UseFormReturn<LoginFormValues> = useForm({
initialValues: { email: '', password: '' }
});
const [isOpen, actions]: UseBooleanReturn = useBoolean(false);Dependencies
react- React librarymobx- MobX state managementmobx-react-lite- React bindings for MobX
Peer Dependencies
Make sure these are installed in your app:
react^19.0.0mobx^6.13.0mobx-react-lite^4.1.0
Contributing
When adding new hooks:
- Follow the existing naming convention
- Add TypeScript types
- Write tests
- Update documentation
- Add usage examples
License
ISC
