Skip to content

Error Handling & Recovery

Patterns for robust error handling and recovery in store operations, including centralized error management and safe event handling.

Centralized Error Handling

Use the framework's centralized error handling system for consistent error management:

tsx
// ✅ CORRECT: Use framework's centralized error handling
import { ErrorHandlers } from '@context-action/react';

function useStoreErrorHandling() {
  const handleStoreError = useCallback((error: Error, context: any) => {
    // Framework provides centralized error handling
    ErrorHandlers.store('Store operation failed', {
      storeName: context.storeName,
      operation: context.operation,
      timestamp: Date.now()
    }, error);
  }, []);

  return { handleStoreError };
}

// Store operations with error handling
function useSafeStoreOperations() {
  const userStore = useAppStore('user');
  
  const safeUpdate = useCallback(async (userData: any) => {
    try {
      userStore.setValue(userData);
    } catch (error) {
      // Framework automatically handles this through centralized error system
      // No need for manual console.error - it's handled centrally
      throw error; // Re-throw to maintain error propagation
    }
  }, [userStore]);
  
  return { safeUpdate };
}

EventBus Memory Safety

EventBus automatically handles memory-heavy objects safely:

tsx
// ✅ CORRECT: EventBus automatically handles memory-heavy objects
function useEventBusSafety() {
  const [eventBus] = useState(() => new EventBus());
  
  const emitSafeEvent = useCallback((eventName: string, data: any) => {
    // EventBus automatically detects and safely handles:
    // - DOM elements
    // - React components  
    // - Large objects
    // - Circular references
    
    eventBus.emit(eventName, data);
  }, [eventBus]);
  
  const handleDOMEvent = useCallback((event: Event) => {
    // Safe to pass DOM events - EventBus extracts only essential metadata
    eventBus.emit('dom-interaction', event);
  }, [eventBus]);
  
  return { emitSafeEvent, handleDOMEvent };
}

Error Recovery Patterns

Graceful Degradation

tsx
const useGracefulStore = (storeName, fallbackValue) => {
  const [error, setError] = useState(null);
  
  try {
    const store = useAppStore(storeName);
    const value = useStoreValue(store);
    
    // Reset error if store is working
    if (error) setError(null);
    
    return { value, error: null, hasError: false };
  } catch (err) {
    if (!error) setError(err);
    
    return { 
      value: fallbackValue, 
      error: err, 
      hasError: true 
    };
  }
};

Retry Mechanisms

tsx
const useStoreWithRetry = (storeName, maxRetries = 3) => {
  const [retryCount, setRetryCount] = useState(0);
  const [lastError, setLastError] = useState(null);
  
  const store = useAppStore(storeName);
  
  const safeOperation = useCallback(async (operation) => {
    for (let attempt = 0; attempt <= maxRetries; attempt++) {
      try {
        const result = await operation(store);
        setRetryCount(0);
        setLastError(null);
        return result;
      } catch (error) {
        setLastError(error);
        setRetryCount(attempt + 1);
        
        if (attempt === maxRetries) {
          throw error;
        }
        
        // Exponential backoff
        await new Promise(resolve => 
          setTimeout(resolve, Math.pow(2, attempt) * 1000)
        );
      }
    }
  }, [store, maxRetries]);
  
  return { safeOperation, retryCount, lastError };
};

Error Boundary Integration

Store Error Boundary

tsx
class StoreErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    // Check if error is store-related
    if (error.name === 'StoreError' || error.context?.storeName) {
      return { hasError: true, error };
    }
    
    // Let other errors bubble up
    throw error;
  }
  
  componentDidCatch(error, errorInfo) {
    // Log store errors with context
    ErrorHandlers.store('Store error boundary caught error', {
      error: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack
    }, error);
  }
  
  render() {
    if (this.state.hasError) {
      return this.props.fallback || <div>Store Error: Unable to load data</div>;
    }
    
    return this.props.children;
  }
}

Best Practices

Error Handling Strategy

  1. Use Centralized System: Leverage framework's error handling
  2. Graceful Degradation: Provide fallback values and states
  3. Error Boundaries: Catch and handle store-specific errors
  4. Retry Logic: Implement retry mechanisms for transient failures

Memory Safety

  • EventBus Integration: Use framework's safe event handling
  • Automatic Cleanup: Rely on framework's automatic memory management
  • Error Context: Provide rich context for error diagnosis
  • Resource Management: Ensure proper cleanup on errors

✅ Do

  • Use framework's centralized error handling system
  • Provide fallback values for critical data
  • Implement retry logic for transient failures
  • Log errors with sufficient context for debugging

❌ Avoid

  • Manual console.error instead of centralized error handling
  • Storing error states directly in application stores
  • Ignoring error propagation and recovery
  • Creating memory leaks in error handling code

Released under the Apache-2.0 License.