You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `listenerApi` object is the second argument to each listener callback. It contains several utility functions that may be called anywhere inside the listener's logic. These can be divided into several categories.
303
+
The `listenerApi` object is the second argument to each listener callback. It contains several utility functions that may be called anywhere inside the listener's logic.
304
+
305
+
```ts no-transpile
306
+
exportinterfaceListenerEffectAPI<
307
+
State,
308
+
DispatchextendsReduxDispatch<AnyAction>,
309
+
ExtraArgument=unknown
310
+
> extendsMiddlewareAPI<Dispatch, State> {
311
+
// NOTE: MiddlewareAPI contains `dispatch` and `getState` already
312
+
313
+
/**
314
+
* Returns the store state as it existed when the action was originally dispatched, _before_ the reducers ran.
315
+
* This function can **only** be invoked **synchronously**, it throws error otherwise.
316
+
*/
317
+
getOriginalState: () =>State
318
+
/**
319
+
* Removes the listener entry from the middleware and prevent future instances of the listener from running.
320
+
* It does **not** cancel any active instances.
321
+
*/
322
+
unsubscribe():void
323
+
/**
324
+
* It will subscribe a listener if it was previously removed, noop otherwise.
325
+
*/
326
+
subscribe():void
327
+
/**
328
+
* Returns a promise that resolves when the input predicate returns `true` or
329
+
* rejects if the listener has been cancelled or is completed.
330
+
*
331
+
* The return value is `true` if the predicate succeeds or `false` if a timeout is provided and expires first.
332
+
*/
333
+
condition:ConditionFunction<State>
334
+
/**
335
+
* Returns a promise that resolves when the input predicate returns `true` or
336
+
* rejects if the listener has been cancelled or is completed.
337
+
*
338
+
* The return value is the `[action, currentState, previousState]` combination that the predicate saw as arguments.
339
+
*
340
+
* The promise resolves to null if a timeout is provided and expires first.
341
+
*/
342
+
take:TakePattern<State>
343
+
/**
344
+
* Cancels all other running instances of this same listener except for the one that made this call.
345
+
*/
346
+
cancelActiveListeners: () =>void
347
+
/**
348
+
* An abort signal whose `aborted` property is set to `true`
349
+
* if the listener execution is either aborted or completed.
Then import and use those pre-typed methods in your components.
@@ -410,7 +485,7 @@ This middleware lets you run additional logic when some action is dispatched, as
410
485
411
486
This middleware is not intended to handle all possible use cases. Like thunks, it provides you with a basic set of primitives (including access to `dispatch` and `getState`), and gives you freedom to write any sync or async logic you want. This is both a strength (you can do anything!) and a weakness (you can do anything, with no guard rails!).
412
487
413
-
The middleware includes several async workflow primitives that are sufficient to write equivalents to many Redux-Saga effects operators like `takeLatest`, `takeLeading`, and `debounce`.
488
+
The middleware includes several async workflow primitives that are sufficient to write equivalents to many Redux-Saga effects operators like `takeLatest`, `takeLeading`, and `debounce`, although none of those methods are directly included. (See [the listener middleware tests file for examples of how to write code equivalent to those effects](https://github.com/reduxjs/redux-toolkit/blob/03eafd5236f16574935cdf1c5958e32ee8cf3fbe/packages/toolkit/src/listenerMiddleware/tests/effectScenarios.test.ts#L74-L363).)
The provided async workflow primitives (`cancelActiveListeners`, `unsuscribe`, `subscribe`, `take`, `condition`, `pause`, `delay`) can be used to implement many of the more complex async workflow capabilities found in the Redux-Saga library. This includes effects such as `throttle`, `debounce`, `takeLatest`, `takeLeading`, and `fork/join`. Some examples from the test suite:
651
+
The provided async workflow primitives (`cancelActiveListeners`, `unsuscribe`, `subscribe`, `take`, `condition`, `pause`, `delay`) can be used to implement behavior that is equivalent to many of the more complex async workflow capabilities found in the Redux-Saga library. This includes effects such as `throttle`, `debounce`, `takeLatest`, `takeLeading`, and `fork/join`. Some examples from the test suite:
577
652
578
653
```js
579
654
test('debounce / takeLatest', async () => {
@@ -729,3 +804,65 @@ While this pattern is _possible_, **we do not necessarily _recommend_ doing this
729
804
At the same time, this _is_ a valid technique, both in terms of API behavior and potential use cases. It's been common to lazy-load sagas as part of a code-split app, and that has often required some complex additional setup work to "inject" sagas. In contrast, `dispatch(addListener())` fits naturally into a React component's lifecycle.
730
805
731
806
So, while we're not specifically encouraging use of this pattern, it's worth documenting here so that users are aware of it as a possibility.
807
+
808
+
### Organizing Listeners in Files
809
+
810
+
As a starting point, **it's best to create the listener middleware in a separate file, such as `app/listenerMiddleware.ts`, rather than in the same file as the store**. This avoids any potential circular import problems from other files trying to import `middleware.addListener`.
811
+
812
+
From there, so far we've come up with three different ways to organize listener functions and setup.
813
+
814
+
First, you can import effect callbacks from slice files into the middleware file, and add the listeners:
0 commit comments