
React Hooks Patterns
- 13 installs
- 1 repo stars
- Updated January 7, 2026
- pluginagentmarketplace/custom-plugin-react
Helps with frontend development tasks.
About
react-hooks-patterns is a Claude Code skill for frontend development. It helps solo builders move faster with AI-assisted development.
- react-hooks-patterns
- Frontend Development
- AI-coding skill
React Hooks Patterns by the numbers
- 13 all-time installs (skills.sh)
- Ranked #1,634 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Jul 18, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-react --skill react-hooks-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 1 |
| Last updated | January 7, 2026 |
| Repository | pluginagentmarketplace/custom-plugin-react ↗ |
What it does
Helps with frontend development tasks.
Files
React Hooks Patterns Skill
Overview
Master React Hooks patterns including built-in hooks (useState, useEffect, useContext, useReducer, useCallback, useMemo) and custom hook development for reusable logic.
Learning Objectives
- Understand all built-in React Hooks
- Create custom hooks for code reuse
- Implement advanced hook patterns
- Optimize performance with hooks
- Handle side effects effectively
Core Hooks
useState
const [state, setState] = useState(initialValue);
// Lazy initialization for expensive computations
const [state, setState] = useState(() => expensiveComputation());
// Functional updates when state depends on previous value
setState(prev => prev + 1);useEffect
useEffect(() => {
// Side effect code
const subscription = api.subscribe();
// Cleanup function
return () => {
subscription.unsubscribe();
};
}, [dependencies]); // Dependency arrayuseContext
const value = useContext(MyContext);
// Best practice: Create custom hook
function useMyContext() {
const context = useContext(MyContext);
if (!context) {
throw new Error('useMyContext must be within Provider');
}
return context;
}useReducer
const [state, dispatch] = useReducer(reducer, initialState);
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
}useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b], // Dependencies
);useMemo
const memoizedValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b]
);useRef
const ref = useRef(initialValue);
// DOM access
const inputRef = useRef(null);
<input ref={inputRef} />
inputRef.current.focus();
// Mutable value that doesn't trigger re-render
const countRef = useRef(0);Custom Hooks Library
useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(url)
.then(res => res.json())
.then(data => {
if (!cancelled) {
setData(data);
setLoading(false);
}
})
.catch(err => {
if (!cancelled) {
setError(err);
setLoading(false);
}
});
return () => {
cancelled = true;
};
}, [url]);
return { data, loading, error };
}useLocalStorage
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}useDebounce
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}usePrevious
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}useToggle
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => {
setValue(v => !v);
}, []);
return [value, toggle];
}useOnClickOutside
function useOnClickOutside(ref, handler) {
useEffect(() => {
const listener = (event) => {
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [ref, handler]);
}Practice Exercises
1. Counter with useReducer: Build a counter using useReducer instead of useState 2. Theme Context: Create a theme switcher using useContext 3. Data Fetching: Implement useFetch with caching 4. Form Handler: Create useForm custom hook for form state management 5. Window Size Hook: Build useWindowSize hook for responsive layouts 6. Intersection Observer: Create useInView hook for lazy loading 7. Timer Hook: Build useInterval and useTimeout hooks
Common Patterns
Fetching with Abort
function useFetchWithAbort(url) {
const [state, setState] = useState({ data: null, loading: true, error: null });
useEffect(() => {
const abortController = new AbortController();
fetch(url, { signal: abortController.signal })
.then(res => res.json())
.then(data => setState({ data, loading: false, error: null }))
.catch(err => {
if (err.name !== 'AbortError') {
setState({ data: null, loading: false, error: err });
}
});
return () => abortController.abort();
}, [url]);
return state;
}Combining Multiple Hooks
function useAuthenticatedApi(url) {
const { token } = useAuth();
const { data, loading, error } = useFetch(url, {
headers: {
Authorization: `Bearer ${token}`
}
});
return { data, loading, error };
}Best Practices
1. Name custom hooks with "use" prefix 2. Extract reusable logic into custom hooks 3. Keep hooks at component top level (no conditionals) 4. Use ESLint plugin for hooks rules 5. Document custom hook dependencies 6. Test custom hooks with @testing-library/react-hooks
Resources
- React Hooks API Reference
- useHooks.com - Collection of custom hooks
- React Hooks Cheatsheet
Assessment
Can you:
- [ ] Explain when to use each built-in hook?
- [ ] Create custom hooks for reusable logic?
- [ ] Handle cleanup in useEffect properly?
- [ ] Optimize with useCallback and useMemo?
- [ ] Manage complex state with useReducer?
- [ ] Build a custom hook library for your project?
---
Unit Test Template
// __tests__/useCustomHook.test.js
import { renderHook, act, waitFor } from '@testing-library/react';
import { useCustomHook } from '../useCustomHook';
describe('useCustomHook', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should initialize with default state', () => {
const { result } = renderHook(() => useCustomHook());
expect(result.current.state).toBe(initialValue);
});
it('should handle async operations', async () => {
const { result } = renderHook(() => useCustomHook());
await act(async () => {
await result.current.asyncAction();
});
await waitFor(() => {
expect(result.current.loading).toBe(false);
});
});
it('should cleanup on unmount', () => {
const cleanup = jest.fn();
const { unmount } = renderHook(() => useCustomHook({ onCleanup: cleanup }));
unmount();
expect(cleanup).toHaveBeenCalled();
});
});Retry Logic Pattern
function useRetryAsync(asyncFn, options = {}) {
const { maxRetries = 3, backoff = 1000 } = options;
const [state, setState] = useState({ data: null, error: null, loading: false });
const execute = useCallback(async (...args) => {
setState(s => ({ ...s, loading: true, error: null }));
let lastError;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const data = await asyncFn(...args);
setState({ data, error: null, loading: false });
return data;
} catch (error) {
lastError = error;
if (attempt < maxRetries) {
await new Promise(r => setTimeout(r, backoff * Math.pow(2, attempt)));
}
}
}
setState({ data: null, error: lastError, loading: false });
throw lastError;
}, [asyncFn, maxRetries, backoff]);
return { ...state, execute };
}---
Version: 2.0.0 Last Updated: 2025-12-30 SASMP Version: 2.0.0 Difficulty: Intermediate Estimated Time: 2-3 weeks Prerequisites: React Fundamentals Changelog: Added retry patterns, test templates, and observability hooks
react_skill: react-hooks-patterns
react-hooks-patterns Guide
#!/usr/bin/env python3
import json
print(json.dumps({"skill": "react-hooks-patterns"}, indent=2))