Skip to content

Commit e20bddb

Browse files
committed
change preventPropagation option to api.stopPropagation method
1 parent 91b1929 commit e20bddb

File tree

4 files changed

+45
-37
lines changed

4 files changed

+45
-37
lines changed

etc/redux-toolkit.api.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ export interface ActionCreatorWithPreparedPayload<Args extends unknown[], P, T e
5151
(...args: Args): PayloadAction<P, T, M, E>;
5252
}
5353

54+
// @alpha (undocumented)
55+
export type ActionListener<A extends AnyAction, S, D extends Dispatch<AnyAction>> = (action: A, api: ActionListenerMiddlewareAPI<S, D>) => void;
56+
57+
// @alpha (undocumented)
58+
export interface ActionListenerMiddlewareAPI<S, D extends Dispatch<AnyAction>> extends MiddlewareAPI<D, S> {
59+
// (undocumented)
60+
stopPropagation(): void;
61+
}
62+
5463
// @public
5564
export interface ActionReducerMapBuilder<State> {
5665
addCase<ActionCreator extends TypedActionCreator<string>>(actionCreator: ActionCreator, reducer: CaseReducer<State, ReturnType<ActionCreator>>): ActionReducerMapBuilder<State>;

src/createActionListenerMiddleware.test.ts

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import { AnyAction } from 'redux'
99

1010
const middlewareApi = {
1111
getState: expect.any(Function),
12-
dispatch: expect.any(Function)
12+
dispatch: expect.any(Function),
13+
stopPropagation: expect.any(Function)
1314
}
1415

1516
const noop = () => {}
@@ -222,27 +223,12 @@ describe('createActionListenerMiddleware', () => {
222223
expect(reducer.mock.calls).toEqual([[{}, testAction1('a')]])
223224
})
224225

225-
test('"preventPropagation" prevents actions from being forwarded to the store', () => {
226+
test('calling `api.stopPropagation` in the listeners prevents actions from being forwarded to the store', () => {
226227
reducer.mockClear()
227228

228-
const listener = jest.fn((_: TestAction1) => {})
229-
230-
middleware.addListener(testAction1, listener, { preventPropagation: true })
231-
232-
store.dispatch(testAction1('a'))
233-
234-
expect(reducer.mock.calls).toEqual([])
235-
})
236-
237-
test('combining "preventPropagation" and "condition', () => {
238-
reducer.mockClear()
239-
240-
const listener = jest.fn((_: TestAction1) => {})
241-
242-
middleware.addListener(testAction1, listener, {
243-
preventPropagation: true,
244-
condition(action) {
245-
return action.payload === 'b'
229+
middleware.addListener(testAction1, (action: TestAction1, api) => {
230+
if (action.payload === 'b') {
231+
api.stopPropagation()
246232
}
247233
})
248234

src/createActionListenerMiddleware.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@ import { Middleware, Dispatch, AnyAction, MiddlewareAPI, Action } from 'redux'
22
import { TypedActionCreator } from './mapBuilders'
33
import { createAction, BaseActionCreator } from './createAction'
44

5-
type ActionListener<A extends AnyAction, S, D extends Dispatch<AnyAction>> = (
6-
action: A,
7-
api: MiddlewareAPI<D, S>
8-
) => void
9-
interface ActionListenerOptions<
5+
/**
6+
* @alpha
7+
*/
8+
export interface ActionListenerMiddlewareAPI<S, D extends Dispatch<AnyAction>>
9+
extends MiddlewareAPI<D, S> {
10+
stopPropagation(): void
11+
}
12+
13+
/**
14+
* @alpha
15+
*/
16+
export type ActionListener<
17+
A extends AnyAction,
18+
S,
19+
D extends Dispatch<AnyAction>
20+
> = (action: A, api: ActionListenerMiddlewareAPI<S, D>) => void
21+
22+
export interface ActionListenerOptions<
1023
A extends AnyAction,
1124
S,
1225
_ extends Dispatch<AnyAction>
@@ -15,21 +28,13 @@ interface ActionListenerOptions<
1528
* Indicates that the listener should be removed after if has run once.
1629
*/
1730
once?: boolean
18-
/**
19-
* If set to true, the action will not be forwarded to
20-
* * listeners that were registered after this listener
21-
* * middlewares later in the middleware chain
22-
* * reducers
23-
* If this listener is skipped due to `options.condition`, this has no effect.
24-
*/
25-
preventPropagation?: boolean
2631
/**
2732
* A function that determines if the listener should run, depending on the action and probably the state.
2833
*/
2934
condition?(action: A, getState: () => S): boolean
3035
}
3136

32-
interface AddListenerAction<
37+
export interface AddListenerAction<
3338
A extends AnyAction,
3439
S,
3540
D extends Dispatch<AnyAction>
@@ -172,11 +177,17 @@ export function createActionListenerMiddleware<
172177
if (listeners) {
173178
for (const entry of listeners) {
174179
if (!entry.condition || entry.condition(action, api.getState)) {
175-
entry.listener(action, api)
180+
let preventPropagation = false
181+
entry.listener(action, {
182+
...api,
183+
stopPropagation() {
184+
preventPropagation = true
185+
}
186+
})
176187
if (entry.once) {
177188
listeners.delete(entry)
178189
}
179-
if (entry.preventPropagation) {
190+
if (preventPropagation) {
180191
return action
181192
}
182193
}

src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ export {
107107
export {
108108
createActionListenerMiddleware,
109109
addListenerAction,
110-
removeListenerAction
110+
removeListenerAction,
111+
ActionListener,
112+
ActionListenerMiddlewareAPI
111113
} from './createActionListenerMiddleware'
112114

113115
export { nanoid } from './nanoid'

0 commit comments

Comments
 (0)