0
# Concurrency Effects
1
2
Effects for managing concurrent execution, forking tasks, and coordinating multiple asynchronous operations.
3
4
## Capabilities
5
6
### fork
7
8
Creates an effect that performs a non-blocking call on a function. Returns a Task object representing the forked execution.
9
10
```typescript { .api }
11
/**
12
* Perform non-blocking call, returns Task object
13
* @param fn - Function to fork (generator, async, or sync)
14
* @param args - Arguments to pass to the function
15
* @returns ForkEffect that resolves with Task
16
*/
17
function fork<Fn extends (...args: any[]) => any>(
18
fn: Fn,
19
...args: Parameters<Fn>
20
): ForkEffect<SagaReturnType<Fn>>;
21
22
/**
23
* Fork method on context object
24
* @param ctxAndFnName - Array of [context, methodName]
25
* @param args - Arguments to pass
26
* @returns ForkEffect
27
*/
28
function fork<Ctx extends { [P in Name]: (this: Ctx, ...args: any[]) => any }, Name extends string>(
29
ctxAndFnName: [Ctx, Name],
30
...args: Parameters<Ctx[Name]>
31
): ForkEffect<SagaReturnType<Ctx[Name]>>;
32
```
33
34
**Usage Examples:**
35
36
```typescript
37
import { fork, take, cancel } from "redux-saga/effects";
38
39
function* backgroundTask() {
40
while (true) {
41
console.log("Background work...");
42
yield delay(1000);
43
}
44
}
45
46
function* mainSaga() {
47
// Fork a background task
48
const task = yield fork(backgroundTask);
49
50
// Fork multiple tasks
51
const task1 = yield fork(fetchUser, 1);
52
const task2 = yield fork(fetchUser, 2);
53
54
// Parent waits for all forked tasks to complete
55
// before terminating (unless cancelled)
56
}
57
```
58
59
### spawn
60
61
Same as `fork()` but creates a detached task. A detached task remains independent from its parent and acts like a top-level task.
62
63
```typescript { .api }
64
/**
65
* Create detached task independent from parent
66
* @param fn - Function to spawn
67
* @param args - Arguments to pass
68
* @returns ForkEffect with detached task
69
*/
70
function spawn<Fn extends (...args: any[]) => any>(
71
fn: Fn,
72
...args: Parameters<Fn>
73
): ForkEffect<SagaReturnType<Fn>>;
74
```
75
76
**Usage Examples:**
77
78
```typescript
79
import { spawn } from "redux-saga/effects";
80
81
function* parentSaga() {
82
// Spawn detached task
83
yield spawn(independentTask);
84
85
// Parent can complete without waiting for spawned task
86
// Spawned task continues running independently
87
}
88
```
89
90
### join
91
92
Creates an effect that waits for the result of a previously forked task. If the joined task is cancelled, the cancellation propagates to the saga executing the join effect.
93
94
```typescript { .api }
95
/**
96
* Wait for result of previously forked task
97
* @param task - Task object from fork effect
98
* @returns JoinEffect that resolves with task result
99
*/
100
function join(task: Task): JoinEffect;
101
102
/**
103
* Wait for results of multiple tasks
104
* @param tasks - Array of Task objects
105
* @returns JoinEffect that resolves when all tasks complete
106
*/
107
function join(tasks: Task[]): JoinEffect;
108
```
109
110
**Usage Examples:**
111
112
```typescript
113
import { fork, join } from "redux-saga/effects";
114
115
function* coordinatorSaga() {
116
// Fork multiple tasks
117
const task1 = yield fork(fetchUser, 1);
118
const task2 = yield fork(fetchUser, 2);
119
120
// Wait for both to complete
121
const [user1, user2] = yield join([task1, task2]);
122
123
// Or join one at a time
124
const result1 = yield join(task1);
125
const result2 = yield join(task2);
126
}
127
```
128
129
### cancel
130
131
Creates an effect that cancels a previously forked task. Cancellation propagates to all child tasks and current effects.
132
133
```typescript { .api }
134
/**
135
* Cancel a previously forked task
136
* @param task - Task object to cancel
137
* @returns CancelEffect
138
*/
139
function cancel(task: Task): CancelEffect;
140
141
/**
142
* Cancel multiple tasks
143
* @param tasks - Array of tasks to cancel
144
* @returns CancelEffect
145
*/
146
function cancel(tasks: Task[]): CancelEffect;
147
148
/**
149
* Self-cancellation (cancel current task)
150
* @returns CancelEffect for self-cancellation
151
*/
152
function cancel(): CancelEffect;
153
```
154
155
**Usage Examples:**
156
157
```typescript
158
import { fork, cancel, take, cancelled } from "redux-saga/effects";
159
160
function* cancellableTask() {
161
try {
162
while (true) {
163
yield call(doWork);
164
yield delay(1000);
165
}
166
} finally {
167
if (yield cancelled()) {
168
console.log('Task was cancelled');
169
// Cleanup logic
170
}
171
}
172
}
173
174
function* controllerSaga() {
175
const task = yield fork(cancellableTask);
176
177
// Cancel on user action
178
yield take('CANCEL_BACKGROUND_TASK');
179
yield cancel(task);
180
}
181
```
182
183
### cancelled
184
185
Creates an effect that returns whether the current generator has been cancelled. Typically used in finally blocks for cleanup.
186
187
```typescript { .api }
188
/**
189
* Check if current generator has been cancelled
190
* @returns CancelledEffect that resolves with boolean
191
*/
192
function cancelled(): CancelledEffect;
193
```
194
195
### all
196
197
Creates an effect that runs multiple effects in parallel and waits for all of them to complete. Similar to `Promise.all()`.
198
199
```typescript { .api }
200
/**
201
* Run multiple effects in parallel, wait for all to complete
202
* @param effects - Array of effects to run in parallel
203
* @returns AllEffect that resolves with array of results
204
*/
205
function all<T>(effects: T[]): AllEffect<T>;
206
207
/**
208
* Run labeled effects in parallel
209
* @param effects - Object with labeled effects
210
* @returns AllEffect that resolves with object of results
211
*/
212
function all<T>(effects: { [key: string]: T }): AllEffect<T>;
213
```
214
215
**Usage Examples:**
216
217
```typescript
218
import { all, call } from "redux-saga/effects";
219
220
function* fetchAllData() {
221
// Run multiple calls in parallel (array form)
222
const [users, posts, comments] = yield all([
223
call(fetchUsers),
224
call(fetchPosts),
225
call(fetchComments)
226
]);
227
228
// Run with labels (object form)
229
const { userData, profileData } = yield all({
230
userData: call(fetchUser, userId),
231
profileData: call(fetchProfile, userId)
232
});
233
}
234
```
235
236
### race
237
238
Creates an effect that runs a race between multiple effects. The first effect to complete wins, and all others are automatically cancelled.
239
240
```typescript { .api }
241
/**
242
* Run race between multiple effects, first to complete wins
243
* @param effects - Object with labeled effects to race
244
* @returns RaceEffect that resolves with winner's result
245
*/
246
function race<T>(effects: { [key: string]: T }): RaceEffect<T>;
247
248
/**
249
* Race with array of effects
250
* @param effects - Array of effects to race
251
* @returns RaceEffect
252
*/
253
function race<T>(effects: T[]): RaceEffect<T>;
254
```
255
256
**Usage Examples:**
257
258
```typescript
259
import { race, call, take, delay } from "redux-saga/effects";
260
261
function* fetchWithTimeout() {
262
const { response, timeout } = yield race({
263
response: call(fetchUser, userId),
264
timeout: delay(5000, 'TIMEOUT')
265
});
266
267
if (timeout) {
268
console.log('Request timed out');
269
} else {
270
console.log('Got response:', response);
271
}
272
}
273
274
function* cancellableFetch() {
275
const { data, cancelled } = yield race({
276
data: call(fetchData),
277
cancelled: take('CANCEL_FETCH')
278
});
279
280
if (cancelled) {
281
console.log('Fetch was cancelled by user');
282
}
283
}
284
```
285
286
### setContext
287
288
Creates an effect that updates the saga's context. This extends the context rather than replacing it.
289
290
```typescript { .api }
291
/**
292
* Update saga's context (extends existing context)
293
* @param props - Properties to add/update in context
294
* @returns SetContextEffect
295
*/
296
function setContext<C extends object>(props: C): SetContextEffect<C>;
297
```
298
299
### getContext
300
301
Creates an effect that returns a specific property of the saga's context.
302
303
```typescript { .api }
304
/**
305
* Get property from saga's context
306
* @param prop - Property name to retrieve
307
* @returns GetContextEffect that resolves with property value
308
*/
309
function getContext(prop: string): GetContextEffect;
310
```
311
312
**Usage Examples:**
313
314
```typescript
315
import { setContext, getContext, call } from "redux-saga/effects";
316
317
function* apiSaga() {
318
// Set context
319
yield setContext({
320
apiClient: new ApiClient(),
321
userId: 123
322
});
323
324
// Get from context
325
const apiClient = yield getContext('apiClient');
326
const userId = yield getContext('userId');
327
328
const data = yield call([apiClient, 'fetchUser'], userId);
329
}
330
```
331
332
### detach
333
334
Detaches a fork effect, making it run independently of its parent.
335
336
```typescript { .api }
337
/**
338
* Detach a fork effect from its parent
339
* @param forkEffect - ForkEffect to detach
340
* @returns Detached ForkEffect
341
*/
342
function detach(forkEffect: ForkEffect): ForkEffect;
343
```
344
345
**Usage Examples:**
346
347
```typescript
348
import { fork, detach } from "redux-saga/effects";
349
350
function* parentSaga() {
351
// Create detached fork
352
yield detach(fork(backgroundService));
353
354
// Parent can complete without waiting for detached task
355
}
356
```