Saga middleware for Redux to handle side effects using ES6 generators
—
Redux-Saga provides several utility packages that offer additional functionality for type checking, promises, symbols, and monitoring.
Utility functions for checking the type of values in Redux-Saga applications.
/**
* Type checking utilities from @redux-saga/is
*/
// Basic type checks
function undef(value: any): value is undefined;
function notUndef(value: any): value is {};
function func(value: any): value is Function;
function number(value: any): value is number;
function string(value: any): value is string;
function array(value: any): value is any[];
function object(value: any): value is object;
// Redux-Saga specific type checks
function promise(value: any): value is Promise<any>;
function iterator(value: any): value is Iterator<any>;
function iterable(value: any): value is Iterable<any>;
function task(value: any): value is Task;
function sagaAction(value: any): boolean;
function observable(value: any): boolean;
function buffer(value: any): value is Buffer<any>;
function pattern(value: any): boolean;
function channel(value: any): value is Channel<any>;
function stringableFunc(value: any): boolean;
function symbol(value: any): value is symbol;
function multicast(value: any): value is MulticastChannel<any>;
function effect(value: any): value is Effect;Usage Examples:
import * as is from "@redux-saga/is";
function* validateInputs(action) {
if (!is.object(action.payload)) {
throw new Error('Payload must be an object');
}
if (is.promise(action.payload.data)) {
const data = yield action.payload.data;
// Handle promise data
}
if (is.channel(action.payload.source)) {
// Handle channel input
const message = yield take(action.payload.source);
}
}Provides access to all symbols used internally by Redux-Saga.
/**
* Redux-Saga symbol constants
*/
const CANCEL: unique symbol;
const SAGA_ACTION: unique symbol;
const TASK: unique symbol;
const SAGA_LOCATION: unique symbol;
const CHANNEL_END_TYPE: unique symbol;
const IO: unique symbol;
const MATCH: unique symbol;
const MULTICAST: unique symbol;
const SELF_CANCELLATION: unique symbol;
const TASK_CANCEL: unique symbol;
const TERMINATE: unique symbol;Usage Examples:
import { CANCEL, SAGA_ACTION } from "@redux-saga/symbols";
function* cancellableSaga() {
try {
yield call(longRunningOperation);
} catch (error) {
if (error === CANCEL) {
console.log('Saga was cancelled');
// Cleanup logic
} else {
throw error;
}
}
}
function* detectSagaActions() {
const action = yield take();
if (action[SAGA_ACTION]) {
console.log('This action was dispatched by a saga');
}
}Utilities for creating deferred promises that can be resolved or rejected externally.
/**
* Create a deferred promise
* @returns Deferred object with promise, resolve, and reject methods
*/
function deferred<T = any>(): Deferred<T>;
/**
* Create an array of deferred promises
* @param length - Number of deferred promises to create
* @returns Array of deferred objects
*/
function arrayOfDeferred<T = any>(length: number): Deferred<T>[];
interface Deferred<T> {
promise: Promise<T>;
resolve(value: T | Promise<T>): void;
reject(reason?: any): void;
}Usage Examples:
import deferred, { arrayOfDeferred } from "@redux-saga/deferred";
function* coordinatedSagas() {
// Create deferred for coordination
const coordination = deferred();
// Start multiple sagas
yield fork(taskA, coordination);
yield fork(taskB, coordination);
// Wait for coordination signal
yield coordination.promise;
console.log('All tasks coordinated');
}
function* batchProcessing() {
const batchSize = 5;
const batch = arrayOfDeferred(batchSize);
// Start batch processing
for (let i = 0; i < batchSize; i++) {
yield fork(processItem, i, batch[i]);
}
// Wait for all items to complete
yield all(batch.map(d => d.promise));
}Promise-based delay utility with cancellation support.
/**
* Create a cancellable delay promise
* @param ms - Milliseconds to delay
* @param value - Optional value to resolve with
* @returns Cancellable promise that resolves after delay
*/
function delay<T = true>(ms: number, value?: T): Promise<T> & { cancel(): void };Usage Examples:
import delay from "@redux-saga/delay-p";
function* timeoutPatternSaga() {
try {
// Create cancellable delay
const delayPromise = delay(5000, 'timeout');
// Use with race for timeout pattern
const { response, timeout } = yield race({
response: call(api.fetchData),
timeout: delayPromise
});
if (timeout) {
console.log('Request timed out');
} else {
console.log('Request completed:', response);
// Cancel the delay to free resources
delayPromise.cancel();
}
} catch (error) {
console.error('Error in timeout pattern:', error);
}
}Basic saga monitor implementation for debugging and logging saga execution.
/**
* Simple saga monitor for logging saga events
* @param options - Configuration options
* @returns SagaMonitor instance
*/
function createSagaMonitor(options?: {
level?: 'info' | 'warning' | 'error';
effectTrigger?: boolean;
effectResolve?: boolean;
effectReject?: boolean;
effectCancel?: boolean;
actionDispatch?: boolean;
}): SagaMonitor;
/**
* Utility function for logging sagas
* @param effect - Effect to log
* @param effectId - Unique effect ID
* @param parentEffectId - Parent effect ID
*/
function logSaga(effect: Effect, effectId: number, parentEffectId?: number): void;Usage Examples:
import createSagaMiddleware from "redux-saga";
import createSagaMonitor from "@redux-saga/simple-saga-monitor";
// Create monitor with custom options
const sagaMonitor = createSagaMonitor({
level: 'info',
effectTrigger: true,
effectResolve: true,
effectReject: true,
actionDispatch: true
});
// Use monitor with saga middleware
const sagaMiddleware = createSagaMiddleware({
sagaMonitor
});
// Monitor will log all saga effects and actions to console// Deferred types
interface Deferred<T> {
promise: Promise<T>;
resolve(value: T): void;
reject(reason?: any): void;
}
// Monitor types
interface SagaMonitor {
rootSagaStarted?(options: { effectId: number; saga: Saga; args: any[] }): void;
effectTriggered?(options: { effectId: number; parentEffectId: number; label: string; effect: Effect }): void;
effectResolved?(options: { effectId: number; result: any }): void;
effectRejected?(options: { effectId: number; error: any }): void;
effectCancelled?(options: { effectId: number }): void;
actionDispatched?(action: AnyAction): void;
}
// Type checking function types
type TypeChecker<T> = (value: any) => value is T;
type BooleanChecker = (value: any) => boolean;Install with Tessl CLI
npx tessl i tessl/npm-redux-saga