add-react-hook
Skill1 starsChanged 9 months agoMITView on GitHub
Create a custom React hook with TypeScript and tests. Use when: extracting reusable stateful logic into a custom hook for a React or Next.js frontend (useState, useEffect, useCallback patterns). Only for React-based stacks — for Vue composables, Svelte stores, or Angular services, read the existing code for that stack instead.
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 13
Create a custom React hook with proper typing and tests.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Add React Hook: $ARGUMENTS
Create a custom React hook with proper typing and tests.
Process
1. Plan the Hook
Determine:
- What state does it manage?
- What side effects does it handle?
- What does it return?
2. Create Hook File
Location: hooks/use[HookName].ts
import { useState, useEffect, useCallback } from 'react';
interface UseHookNameOptions {
// configuration options
initialValue?: string;
}
interface UseHookNameReturn {
// return type
value: string;
setValue: (value: string) => void;
isLoading: boolean;
error: Error | null;
}
export function useHookName(options: UseHookNameOptions = {}): UseHookNameReturn {
const { initialValue = '' } = options;
const [value, setValue] = useState(initialValue);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
const handleSetValue = useCallback((newValue: string) => {
setValue(newValue);
}, []);
useEffect(() => {
// Side effects here
}, []);
return {
value,
setValue: handleSetValue,
isLoading,
error,
};
}3. Add to Exports
// hooks/index.ts
export { useHookName } from './useHookName';4. Create Tests
// hooks/useHookName.test.ts
import { renderHook, act } from '@testing-library/react';
import { useHookName } from './useHookName';
describe('useHookName', () => {
test('returns initial value', () => {
const { result } = renderHook(() => useHookName());
expect(result.current.value).toBe('');
});
test('updates value', () => {
const { result } = renderHook(() => useHookName());
act(() => {
result.current.setValue('new value');
});
expect(result.current.value).toBe('new value');
});
test('accepts initial value option', () => {
const { result } = renderHook(() =>
useHookName({ initialValue: 'custom' })
);
expect(result.current.value).toBe('custom');
});
});5. Validate
npm run build
npm run lint
npm testCommon Hook Patterns
Data fetching:
export function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
// ...
}Local storage:
export function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
// ...
}Debounce:
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
// ...
}Media query:
export function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(false);
// ...
}In this repository28 other files it gives its agents.
- angular-spring-ui/CLAUDE.mdCLAUDE.md
- angular-ui/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- fastapi/CLAUDE.mdCLAUDE.md
- go-api/CLAUDE.mdCLAUDE.md
- hono-api/CLAUDE.mdCLAUDE.md
- lambda-api/CLAUDE.mdCLAUDE.md
- nest-api/CLAUDE.mdCLAUDE.md
- nest-history-api/CLAUDE.mdCLAUDE.md
- nuxt-api/CLAUDE.mdCLAUDE.md
- rails-api/CLAUDE.mdCLAUDE.md
- spring-api/CLAUDE.mdCLAUDE.md
- svelte-ui/CLAUDE.mdCLAUDE.md
- tanstack-ui/CLAUDE.mdCLAUDE.md
- tests/CLAUDE.mdCLAUDE.md
- vue-ui/CLAUDE.mdCLAUDE.md
- .github/agents/copilot-instructions.mdCopilot instructions
- .github/copilot-instructions.mdCopilot instructions
- add-react-componentSkill
- add-react-testSkill
- debugSkill
- document-featureSkill
- e2e-testSkill
- fix-buildSkill
- perf-auditSkill
- refactorSkill
- run-e2eSkill
- update-depsSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

