Skip to content

Dispatch Patterns ​

Core action dispatching patterns for the Context-Action framework, including execution modes, filtering, and performance optimization.

Import ​

typescript
import { createActionContext, ActionPayloadMap } from '@context-action/react';

Prerequisites ​

For complete setup instructions including type definitions, context creation, and provider configuration, see Basic Action Setup.

This document uses the AppActions pattern from the setup guide:

The examples assume you have configured the following context:

typescript
interface AppActions extends ActionPayloadMap {
  updateUser: { id: string; name: string; email: string };
  processOrder: { orderId: string; items: any[]; total: number };
  broadcastEvent: { event: string; data: any };
  fastestResponse: { query: string };
  sensitiveOperation: { token: string; data: any };
  dynamicAction: { type: string; payload: any };
  slowOperation: { complexData: any };
  criticalAction: { priority: number; data: any };
  riskyAction: { operation: string };
  bestEffortAction: { data: any };
}

const {
  Provider: AppActionProvider,
  useActionDispatch: useAppDispatch,
  useActionHandler: useAppHandler,
  useActionRegister: useAppRegister
} = createActionContext<AppActions>('App');

Basic Dispatch ​

Simple action dispatching without result collection.

typescript
function UserComponent() {
  const dispatch = useAppDispatch();
  
  const handleUserUpdate = async () => {
    // Basic action dispatch
    await dispatch('updateUser', { id: '123', name: 'John', email: 'john@example.com' });
  };
  
  const handleOrderProcess = async (orderData) => {
    // Dispatch with execution options
    await dispatch('processOrder', orderData, {
      executionMode: 'parallel',
      timeout: 5000
    });
  };
  
  return (
    <div>
      <button onClick={handleUserUpdate}>Update User</button>
      <button onClick={() => handleOrderProcess(orderData)}>Process Order</button>
    </div>
  );
}

Execution Modes ​

Control how multiple handlers for the same action are executed.

Sequential Execution (Default) ​

typescript
function OrderComponent() {
  const dispatch = useAppDispatch();
  
  const handleProcessOrder = async (orderData) => {
    // Handlers execute one after another in priority order
    await dispatch('processOrder', orderData, {
      executionMode: 'sequential'
    });
  };
  
  return <button onClick={() => handleProcessOrder(orderData)}>Process Order</button>;
}

Handlers execute in sequence, allowing early handlers to modify payload for later ones.

Parallel Execution ​

typescript
function EventComponent() {
  const dispatch = useAppDispatch();
  
  const handleBroadcast = async (eventData) => {
    // All handlers execute simultaneously
    await dispatch('broadcastEvent', eventData, {
      executionMode: 'parallel'
    });
  };
  
  return <button onClick={() => handleBroadcast(eventData)}>Broadcast Event</button>;
}

Best for independent operations like analytics, logging, and notifications.

When result collection is enabled, results are assembled in the registered priority order after all parallel handlers settle. Completion timing affects when side effects finish, but does not change the meaning of first, last, or all result strategies.

Race Execution ​

typescript
function SearchComponent() {
  const dispatch = useAppDispatch();
  
  const handleFastSearch = async (queryData) => {
    // First completed handler wins
    await dispatch('fastestResponse', queryData, {
      executionMode: 'race'
    });
  };
  
  return <button onClick={() => handleFastSearch(queryData)}>Fast Search</button>;
}

Useful for fallback mechanisms and performance-critical operations.

Handler Filtering ​

Fine-grained control over which handlers execute.

Tag-Based Filtering ​

typescript
function UserManagementComponent() {
  const dispatch = useAppDispatch();
  
  const handleUserUpdate = async (payload) => {
    await dispatch('updateUser', payload, {
      filter: {
        handlerIds: ['validator', 'business-logic'],
        excludeHandlerIds: ['analytics', 'logging']
      }
    });
  };
  
  return <button onClick={() => handleUserUpdate(userData)}>Update User</button>;
}

Handler ID Filtering ​

typescript
function SecurityComponent() {
  const dispatch = useAppDispatch();
  
  const handleSensitiveOperation = async (data) => {
    // Only execute security-related handlers
    await dispatch('sensitiveOperation', data, {
      filter: {
        handlerIds: ['security-check'],
        excludeHandlerIds: ['analytics']
      }
    });
  };
  
  return <button onClick={() => handleSensitiveOperation(secureData)}>Secure Operation</button>;
}

Custom Handler Filtering ​

typescript
function DynamicActionComponent() {
  const dispatch = useAppDispatch();
  
  const handleDynamicAction = async (payload) => {
    await dispatch('dynamicAction', payload, {
      filter: {
        custom: (config) => {
          // Complex filtering logic
          return config.priority > 50 && 
                 !config.id?.includes('optional');
        }
      }
    });
  };
  
  return <button onClick={() => handleDynamicAction(dynamicData)}>Dynamic Action</button>;
}

Performance Optimization ​

Timeout Control ​

typescript
function SlowOperationComponent() {
  const dispatch = useAppDispatch();
  
  const handleSlowOperation = async (data) => {
    // Set timeout for action execution
    await dispatch('slowOperation', data, {
      timeout: 10000  // 10 second timeout
    });
  };
  
  return <button onClick={() => handleSlowOperation(complexData)}>Start Slow Operation</button>;
}

Priority-Based Execution ​

typescript
function CriticalActionComponent() {
  const dispatch = useAppDispatch();
  
  const handleCriticalAction = async (payload) => {
    // Execute only high-priority handlers
    await dispatch('criticalAction', payload, {
      filter: {
        custom: (config) => config.priority >= 80
      }
    });
  };
  
  return <button onClick={() => handleCriticalAction(criticalData)}>Critical Action</button>;
}

Error Handling ​

Basic Error Handling ​

typescript
function RiskyActionComponent() {
  const dispatch = useAppDispatch();
  
  const handleRiskyAction = async (payload) => {
    try {
      await dispatch('riskyAction', payload);
    } catch (error) {
      console.error('Action failed:', error);
    }
  };
  
  return <button onClick={() => handleRiskyAction(riskyData)}>Risky Action</button>;
}

Silent Failures ​

typescript
function BestEffortComponent() {
  const register = useAppRegister();
  
  const handleBestEffortAction = async (payload) => {
    // Use dispatchWithResult when callers need per-handler failure details.
    const result = await register.dispatchWithResult('bestEffortAction', payload, {
      result: { collect: true }
    });
    if (result.outcome === 'completed_with_errors') {
      console.error('Some handlers failed:', result.errors);
    }
  };
  
  return <button onClick={() => handleBestEffortAction(effortData)}>Best Effort Action</button>;
}

Real-World Examples ​

Released under the Apache-2.0 License.