Skip to content

refactor: Extract useMounted hook to reduce code duplication #283

@claude

Description

@claude

Problem

The isMountedRef pattern is duplicated across 4+ sheet components to prevent state updates on unmounted components.

Duplicated Pattern

const isMountedRef = useRef(true);
useEffect(() => {
  isMountedRef.current = true;
  return () => {
    isMountedRef.current = false;
  };
}, []);

Affected Files

  1. components/sheets/LogSlipUpSheet.tsx (lines 136-142)
  2. components/sheets/TaskCompletionSheet.tsx (lines 115-121)
  3. components/sheets/EditDisplayNameSheet.tsx (lines 136-142)
  4. components/TaskCreationSheet.tsx (lines 115-123)

Proposed Solution

Create a reusable custom hook in hooks/useMounted.ts:

import { useRef, useEffect } from 'react';

/**
 * Hook to track component mount state.
 * Useful for preventing state updates after unmount in async operations.
 * 
 * @returns Ref that is true while component is mounted, false after unmount
 * @example
 * const isMounted = useMounted();
 * 
 * async function fetchData() {
 *   const result = await api.fetch();
 *   if (isMounted.current) {
 *     setData(result);
 *   }
 * }
 */
export function useMounted(): React.MutableRefObject<boolean> {
  const isMountedRef = useRef(true);
  
  useEffect(() => {
    isMountedRef.current = true;
    return () => {
      isMountedRef.current = false;
    };
  }, []);
  
  return isMountedRef;
}

Usage After Refactor

import { useMounted } from '@/hooks/useMounted';

function MySheet() {
  const isMounted = useMounted();
  
  const handleSave = async () => {
    await saveData();
    if (isMounted.current) {
      dismiss();
    }
  };
}

Benefits

  • DRY principle - single source of truth
  • Consistent behavior across components
  • Easier to test in isolation
  • Self-documenting through JSDoc

Acceptance Criteria

  • Create hooks/useMounted.ts with JSDoc
  • Create __tests__/hooks/useMounted.test.ts
  • Update all 4 sheet components to use hook
  • No functionality regression

Related to #279 (Daily Codebase Review)

Metadata

Metadata

Assignees

No one assigned

    Labels

    refactorCode refactoring

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions