Claude-skill-registry add-hook-whatifwedigdeeper-application-tracker

Create a custom React hook with TypeScript and tests

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/add-hook-whatifwedigdeeper-application-tracker" ~/.claude/skills/majiayu000-claude-skill-registry-add-hook-whatifwedigdeeper-application-tracker && rm -rf "$T"
manifest: skills/data/add-hook-whatifwedigdeeper-application-tracker/SKILL.md
source content

Add 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 test

Common 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);
  // ...
}