Hooks Reference

Custom React hooks in KB/src/hooks/. All use TypeScript and follow standard React conventions.


useChat

File: src/hooks/useChat.ts

Signature:

function useChat(anthropicKey: string): {
  messages: ChatMessage[];
  isLoading: boolean;
  sendMessage: (content: string, currentArticleContext?: string) => Promise<void>;
  clearMessages: () => void;
}

Purpose: Manages the full chat conversation lifecycle with the Claude API via server-sent events (SSE).

Key Features:

  • Message history: Maintains an array of ChatMessage objects with unique IDs (msg_${timestamp}_${random})
  • Streaming support: Creates a placeholder assistant message with isStreaming: true, then progressively updates its content as SSE chunks arrive
  • SSE parsing: Reads response.body.getReader(), decodes text, splits on \n, and extracts data: payloads
  • Article context: When currentArticleContext is provided, injects it as a systemContext field in the POST body, giving Claude awareness of the article the user is reading
  • Error handling: API failures update the streaming message with an error explanation and prompt to check settings
  • Headers: Sends X-Anthropic-Key, X-Serper-Key (from localStorage), and X-Model with each request
  • History preservation: Builds the full message history in Anthropic format (alternating user/assistant roles) for multi-turn conversations

Dependencies: isLoading, messages, anthropicKey (memoized via useCallback)


useSearch

File: src/hooks/useSearch.ts

Signature:

function useSearch(articles: KBArticle[]): {
  query: (term: string) => KBArticle[];
  results: KBArticle[];
  searchTerm: string;
  setSearchTerm: (term: string) => void;
  clearSearch: () => void;
}

Purpose: Fuzzy full-text search across the KB article library using Fuse.js.

Key Features:

  • Fuse.js configuration:
    • keys: title (weight 0.5), summary (weight 0.3), tags (weight 0.2)
    • threshold: 0.35 (moderate fuzziness)
    • minMatchCharLength: 2
    • includeScore: true (for potential ranking UI)
  • Auto-search: useEffect automatically re-runs search when searchTerm changes (minimum 2 chars)
  • Lazy initialization: Fuse index is built once when articles changes via useRef
  • Clear function: Resets both searchTerm and results

Usage: Primarily consumed by Sidebar for the search input and SearchResults dropdown.


useSettings

File: src/hooks/useSettings.ts

Signature:

function useSettings(): {
  settings: Settings;
  updateSettings: (patch: Partial<Settings>) => void;
  hasAnthropicKey: boolean;
}

Purpose: Persistent settings management backed by localStorage.

Key Features:

  • Storage keys:
    • kb_anthropic_key — Anthropic API key
    • kb_serper_key — Serper.dev API key
    • kb_model — Selected Claude model (default: claude-opus-4-6)
  • Lazy loading: Reads from localStorage on first render via initializer function
  • Atomic updates: updateSettings merges partial patches, writes changed keys to localStorage, and updates React state
  • Derived state: hasAnthropicKey is a boolean computed from whether anthropicKey.trim().length > 0

Security note: Keys are stored in browser localStorage and sent via request headers. They are never persisted server-side.


useTheme

File: src/hooks/useTheme.ts

Signature:

function useTheme(): {
  isDark: boolean;
  toggleTheme: () => void;
}

Purpose: Dark/light theme toggle with system preference fallback.

Key Features:

  • Storage key: kb_theme in localStorage
  • System preference fallback: If no stored preference, checks window.matchMedia('(prefers-color-scheme: dark)')
  • DOM synchronization: applyTheme() adds/removes dark class on document.documentElement immediately on initialization and on every change
  • Persistence: useEffect writes back to localStorage whenever theme changes
  • Toggle: Simple dark ↔ light flip via useCallback

Integration: Consumed by ThemeToggle component and applied globally via Tailwind’s darkMode: "class" strategy.

See also