0
# Redux-Saga
1
2
Redux-Saga is a library that makes application side effects (asynchronous things like data fetching and impure things like accessing the browser cache) easier to manage, more efficient to execute, easy to test, and better at handling failures. It uses ES6 generator functions to make asynchronous flows easy to read, write and test, creating a mental model where sagas act as separate threads solely responsible for side effects.
3
4
## Package Information
5
6
- **Package Name**: redux-saga
7
- **Package Type**: npm
8
- **Language**: JavaScript/TypeScript
9
- **Installation**: `npm install redux-saga`
10
11
## Core Imports
12
13
```typescript
14
import createSagaMiddleware from "redux-saga";
15
import { take, put, call, fork, select } from "redux-saga/effects";
16
```
17
18
For CommonJS:
19
20
```javascript
21
const createSagaMiddleware = require("redux-saga").default;
22
const { take, put, call, fork, select } = require("redux-saga/effects");
23
```
24
25
## Basic Usage
26
27
```typescript
28
import { createStore, applyMiddleware } from "redux";
29
import createSagaMiddleware from "redux-saga";
30
import { take, put, call, fork } from "redux-saga/effects";
31
32
// Create saga middleware
33
const sagaMiddleware = createSagaMiddleware();
34
35
// Apply middleware to store
36
const store = createStore(
37
reducer,
38
applyMiddleware(sagaMiddleware)
39
);
40
41
// Example saga
42
function* fetchUserSaga(action) {
43
try {
44
const user = yield call(Api.fetchUser, action.payload.userId);
45
yield put({ type: 'USER_FETCH_SUCCEEDED', user });
46
} catch (e) {
47
yield put({ type: 'USER_FETCH_FAILED', message: e.message });
48
}
49
}
50
51
function* watchFetchUser() {
52
yield take('USER_FETCH_REQUESTED', fetchUserSaga);
53
}
54
55
// Start the saga
56
sagaMiddleware.run(watchFetchUser);
57
```
58
59
## Architecture
60
61
Redux-Saga is built around several key concepts:
62
63
- **Generator Functions**: ES6 generators that can be paused and resumed, making async code look synchronous
64
- **Effects**: Plain JavaScript objects that describe what the saga should do (declarative)
65
- **Middleware**: Redux middleware that connects sagas to the Redux store
66
- **Tasks**: Objects representing running generator functions that can be cancelled or joined
67
- **Channels**: Communication mechanism between sagas and external event sources
68
69
## Capabilities
70
71
### Middleware Creation
72
73
Core functionality for creating and configuring the Redux middleware that connects sagas to your Redux store.
74
75
```typescript { .api }
76
interface SagaMiddlewareOptions<C extends object = {}> {
77
context?: C;
78
sagaMonitor?: SagaMonitor;
79
onError?(error: Error, errorInfo: ErrorInfo): void;
80
effectMiddlewares?: EffectMiddleware[];
81
channel?: MulticastChannel<Action>;
82
}
83
84
interface SagaMiddleware<C extends object = {}> extends Middleware {
85
run<S extends Saga>(saga: S, ...args: Parameters<S>): Task;
86
setContext(props: Partial<C>): void;
87
}
88
89
function createSagaMiddleware<C extends object>(
90
options?: SagaMiddlewareOptions<C>
91
): SagaMiddleware<C>;
92
```
93
94
[Middleware](./middleware.md)
95
96
### Basic Effects
97
98
Core effects for the most common saga operations: waiting for actions, dispatching actions, calling functions, and managing context.
99
100
```typescript { .api }
101
function take<A extends Action>(pattern?: ActionPattern<A>): TakeEffect;
102
103
function put<A extends Action>(action: A): PutEffect<A>;
104
105
function call<Fn extends (...args: any[]) => any>(
106
fn: Fn,
107
...args: Parameters<Fn>
108
): CallEffect<SagaReturnType<Fn>>;
109
110
function select<Fn extends (state: any, ...args: any[]) => any>(
111
selector?: Fn,
112
...args: Tail<Parameters<Fn>>
113
): SelectEffect;
114
115
function getContext(prop: string): GetContextEffect;
116
117
function setContext(props: object): SetContextEffect;
118
```
119
120
[Basic Effects](./basic-effects.md)
121
122
### Concurrency Effects
123
124
Effects for managing concurrent execution, forking tasks, and coordinating multiple asynchronous operations.
125
126
```typescript { .api }
127
function fork<Fn extends (...args: any[]) => any>(
128
fn: Fn,
129
...args: Parameters<Fn>
130
): ForkEffect<SagaReturnType<Fn>>;
131
132
function spawn<Fn extends (...args: any[]) => any>(
133
fn: Fn,
134
...args: Parameters<Fn>
135
): ForkEffect<SagaReturnType<Fn>>;
136
137
function join(task: Task): JoinEffect;
138
139
function cancel(task: Task): CancelEffect;
140
141
function all<T>(effects: T[]): AllEffect<T>;
142
143
function race<T>(effects: { [key: string]: T }): RaceEffect<T>;
144
```
145
146
[Concurrency Effects](./concurrency-effects.md)
147
148
### Helper Effects
149
150
High-level helper effects built on top of basic effects for common patterns like handling every action, latest action, or throttling.
151
152
```typescript { .api }
153
function takeEvery<P extends ActionPattern>(
154
pattern: P,
155
worker: (action: ActionMatchingPattern<P>) => any
156
): ForkEffect<never>;
157
158
function takeLatest<P extends ActionPattern>(
159
pattern: P,
160
worker: (action: ActionMatchingPattern<P>) => any
161
): ForkEffect<never>;
162
163
function takeLeading<P extends ActionPattern>(
164
pattern: P,
165
worker: (action: ActionMatchingPattern<P>) => any
166
): ForkEffect<never>;
167
168
function throttle<P extends ActionPattern>(
169
ms: number,
170
pattern: P,
171
worker: (action: ActionMatchingPattern<P>) => any
172
): ForkEffect<never>;
173
174
function debounce<P extends ActionPattern>(
175
ms: number,
176
pattern: P,
177
worker: (action: ActionMatchingPattern<P>) => any
178
): ForkEffect<never>;
179
```
180
181
[Helper Effects](./helper-effects.md)
182
183
### Channels
184
185
Channel system for communication between sagas and external event sources, enabling integration with WebSockets, DOM events, and other async data sources.
186
187
```typescript { .api }
188
function channel<T extends NotUndefined>(buffer?: Buffer<T>): Channel<T>;
189
190
function eventChannel<T extends NotUndefined>(
191
subscribe: Subscribe<T>,
192
buffer?: Buffer<T>
193
): EventChannel<T>;
194
195
function multicastChannel<T extends NotUndefined>(): MulticastChannel<T>;
196
197
function actionChannel(
198
pattern: ActionPattern,
199
buffer?: Buffer<Action>
200
): ActionChannelEffect;
201
```
202
203
[Channels](./channels.md)
204
205
### Testing Utilities
206
207
Tools for testing sagas in isolation, including cloneable generators and mock tasks.
208
209
```typescript { .api }
210
function cloneableGenerator<S extends Saga>(
211
saga: S
212
): (...args: Parameters<S>) => SagaIteratorClone;
213
214
function createMockTask(): MockTask;
215
```
216
217
[Testing](./testing.md)
218
219
### Utility Functions
220
221
General utility functions for working with Redux-Saga effects and values.
222
223
```typescript { .api }
224
function detach<T>(forkEffect: ForkEffect<T>): ForkEffect<T>;
225
function isEnd(value: any): value is END;
226
```
227
228
### Utility Packages
229
230
Additional utility packages providing type checking, symbols, deferred promises, and monitoring capabilities.
231
232
```typescript { .api }
233
// Type checking utilities
234
import * as is from "@redux-saga/is";
235
236
// Symbol constants
237
import { CANCEL, SAGA_ACTION, TASK } from "@redux-saga/symbols";
238
239
// Deferred promises
240
import deferred from "@redux-saga/deferred";
241
242
// Promise-based delay
243
import delay from "@redux-saga/delay-p";
244
245
// Saga monitoring
246
import createSagaMonitor from "@redux-saga/simple-saga-monitor";
247
```
248
249
[Utilities](./utilities.md)
250
251
## Types
252
253
### Core Types
254
255
```typescript { .api }
256
interface Action<T extends string = string> {
257
type: T;
258
}
259
260
interface AnyAction extends Action {
261
[extraProps: string]: any;
262
}
263
264
interface Task {
265
isRunning(): boolean;
266
result<T = any>(): T | undefined;
267
error(): any | undefined;
268
toPromise<T = any>(): Promise<T>;
269
cancel(): void;
270
setContext(props: object): void;
271
}
272
273
type ActionPattern<A extends Action = Action> =
274
| string
275
| string[]
276
| ((action: A) => boolean)
277
| A['type'][];
278
279
type NotUndefined = {} | null;
280
281
interface Saga<Args extends any[] = any[], Return = any> {
282
(...args: Args): SagaIterator<Return>;
283
}
284
285
interface SagaIterator<T = any> extends Iterator<any, T, any> {
286
readonly name: string;
287
}
288
289
interface Buffer<T> {
290
isEmpty(): boolean;
291
put(message: T): void;
292
take(): T | undefined;
293
}
294
295
interface TakeableChannel<T> {
296
take(cb: (message: T | END) => void): void;
297
}
298
299
interface PuttableChannel<T> {
300
put(message: T | END): void;
301
}
302
303
interface FlushableChannel<T> {
304
flush(cb: (items: T[] | END) => void): void;
305
}
306
307
interface Channel<T> extends TakeableChannel<T>, PuttableChannel<T>, FlushableChannel<T> {
308
close(): void;
309
}
310
311
interface MulticastChannel<T> extends Channel<T> {
312
take(cb: (message: T | END) => void, matcher?: Predicate<T>): void;
313
}
314
315
type Predicate<T> = (value: T) => boolean;
316
type END = { type: 'END' };
317
type EndType = END;
318
```
319
320
### Effect Types
321
322
```typescript { .api }
323
type TakeEffect = SimpleEffect<'TAKE', TakeEffectDescriptor>;
324
type PutEffect<A extends Action = AnyAction> = SimpleEffect<'PUT', PutEffectDescriptor<A>>;
325
type CallEffect<RT = any> = SimpleEffect<'CALL', CallEffectDescriptor<RT>>;
326
type ForkEffect<RT = any> = SimpleEffect<'FORK', ForkEffectDescriptor<RT>>;
327
type SelectEffect = SimpleEffect<'SELECT', SelectEffectDescriptor>;
328
type GetContextEffect = SimpleEffect<'GET_CONTEXT', GetContextEffectDescriptor>;
329
type SetContextEffect = SimpleEffect<'SET_CONTEXT', SetContextEffectDescriptor>;
330
type AllEffect<T> = CombinatorEffect<'ALL', T>;
331
type RaceEffect<T> = CombinatorEffect<'RACE', T>;
332
333
interface SimpleEffect<T, P> {
334
type: T;
335
payload: P;
336
}
337
338
interface CombinatorEffect<T, P> {
339
type: T;
340
payload: P;
341
}
342
343
type ActionMatchingPattern<P> = P extends string
344
? Action<P>
345
: P extends (action: infer A) => boolean
346
? A extends Action ? A : Action
347
: Action;
348
349
type SagaReturnType<S extends Function> = S extends (...args: any[]) => SagaIterator<infer RT>
350
? RT
351
: S extends (...args: any[]) => Promise<infer RT>
352
? RT
353
: S extends (...args: any[]) => infer RT
354
? RT
355
: never;
356
357
type Tail<L extends any[]> = L extends [any, ...infer T] ? T : never;
358
```
359
360
### Constants
361
362
```typescript { .api }
363
/** Symbol used for cancellation */
364
const CANCEL: string;
365
366
/** Special action type that terminates sagas */
367
const END: EndType;
368
369
/** Effect type constants */
370
const effectTypes: {
371
TAKE: 'TAKE';
372
PUT: 'PUT';
373
ALL: 'ALL';
374
RACE: 'RACE';
375
CALL: 'CALL';
376
CPS: 'CPS';
377
FORK: 'FORK';
378
JOIN: 'JOIN';
379
CANCEL: 'CANCEL';
380
SELECT: 'SELECT';
381
ACTION_CHANNEL: 'ACTION_CHANNEL';
382
CANCELLED: 'CANCELLED';
383
FLUSH: 'FLUSH';
384
GET_CONTEXT: 'GET_CONTEXT';
385
SET_CONTEXT: 'SET_CONTEXT';
386
};
387
```