Skip to content

Commit c65558a

Browse files
committed
Fix listener logic to properly compare combination of effect and predicate/type
1 parent 98d7753 commit c65558a

File tree

2 files changed

+29
-19
lines changed

2 files changed

+29
-19
lines changed

packages/toolkit/src/listenerMiddleware/index.ts

+28-19
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Action, Dispatch, MiddlewareAPI, UnknownAction } from 'redux'
22
import { isAction } from 'redux'
33
import type { ThunkDispatch } from 'redux-thunk'
44
import { createAction } from '../createAction'
5-
import { getOrInsertComputed } from '../utils'
5+
import { nanoid } from '../nanoid'
66

77
import {
88
TaskAbortError,
@@ -221,6 +221,7 @@ export const createListenerEntry: TypedCreateListenerEntry<unknown> =
221221
const { type, predicate, effect } = getListenerEntryPropsFrom(options)
222222

223223
const entry: ListenerEntry<unknown> = {
224+
id: nanoid(),
224225
effect,
225226
type,
226227
predicate,
@@ -235,6 +236,22 @@ export const createListenerEntry: TypedCreateListenerEntry<unknown> =
235236
{ withTypes: () => createListenerEntry },
236237
) as unknown as TypedCreateListenerEntry<unknown>
237238

239+
const findListenerEntry = (
240+
listenerMap: Map<string, ListenerEntry>,
241+
options: FallbackAddListenerOptions,
242+
) => {
243+
const { type, effect, predicate } = getListenerEntryPropsFrom(options)
244+
245+
return Array.from(listenerMap.values()).find((entry) => {
246+
const matchPredicateOrType =
247+
typeof type === 'string'
248+
? entry.type === type
249+
: entry.predicate === predicate
250+
251+
return matchPredicateOrType && entry.effect === effect
252+
})
253+
}
254+
238255
const cancelActiveListeners = (
239256
entry: ListenerEntry<unknown, Dispatch<UnknownAction>>,
240257
) => {
@@ -244,7 +261,7 @@ const cancelActiveListeners = (
244261
}
245262

246263
const createClearListenerMiddleware = (
247-
listenerMap: Map<ListenerEntry['effect'], ListenerEntry>,
264+
listenerMap: Map<string, ListenerEntry>,
248265
) => {
249266
return () => {
250267
listenerMap.forEach(cancelActiveListeners)
@@ -321,15 +338,15 @@ export const createListenerMiddleware = <
321338
>(
322339
middlewareOptions: CreateListenerMiddlewareOptions<ExtraArgument> = {},
323340
) => {
324-
const listenerMap = new Map<ListenerEntry['effect'], ListenerEntry>()
341+
const listenerMap = new Map<string, ListenerEntry>()
325342
const { extra, onError = defaultErrorHandler } = middlewareOptions
326343

327344
assertFunction(onError, 'onError')
328345

329346
const insertEntry = (entry: ListenerEntry) => {
330-
entry.unsubscribe = () => listenerMap.delete(entry.effect)
347+
entry.unsubscribe = () => listenerMap.delete(entry.id)
331348

332-
listenerMap.set(entry.effect, entry)
349+
listenerMap.set(entry.id, entry)
333350
return (cancelOptions?: UnsubscribeListenerOptions) => {
334351
entry.unsubscribe()
335352
if (cancelOptions?.cancelActive) {
@@ -339,9 +356,10 @@ export const createListenerMiddleware = <
339356
}
340357

341358
const startListening = ((options: FallbackAddListenerOptions) => {
342-
const entry = getOrInsertComputed(listenerMap, options.effect, () =>
343-
createListenerEntry(options as any),
344-
)
359+
const entry =
360+
findListenerEntry(listenerMap, options) ??
361+
createListenerEntry(options as any)
362+
345363
return insertEntry(entry)
346364
}) as AddListenerOverloads<any>
347365

@@ -352,16 +370,7 @@ export const createListenerMiddleware = <
352370
const stopListening = (
353371
options: FallbackAddListenerOptions & UnsubscribeListenerOptions,
354372
): boolean => {
355-
const { type, effect, predicate } = getListenerEntryPropsFrom(options)
356-
357-
const entry = Array.from(listenerMap.values()).find((entry) => {
358-
const matchPredicateOrType =
359-
typeof type === 'string'
360-
? entry.type === type
361-
: entry.predicate === predicate
362-
363-
return matchPredicateOrType && entry.effect === effect
364-
})
373+
const entry = findListenerEntry(listenerMap, options)
365374

366375
if (entry) {
367376
entry.unsubscribe()
@@ -410,7 +419,7 @@ export const createListenerMiddleware = <
410419
fork: createFork(internalTaskController.signal, autoJoinPromises),
411420
unsubscribe: entry.unsubscribe,
412421
subscribe: () => {
413-
listenerMap.set(entry.effect, entry)
422+
listenerMap.set(entry.id, entry)
414423
},
415424
cancelActiveListeners: () => {
416425
entry.pending.forEach((controller, _, set) => {

packages/toolkit/src/listenerMiddleware/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ export type ListenerEntry<
845845
State = unknown,
846846
DispatchType extends Dispatch = Dispatch,
847847
> = {
848+
id: string
848849
effect: ListenerEffect<any, State, DispatchType>
849850
unsubscribe: () => void
850851
pending: Set<AbortController>

0 commit comments

Comments
 (0)