diff --git a/examples/action-listener/counter/package.json b/examples/action-listener/counter/package.json
index 566062a4f6..f5e5e5b068 100644
--- a/examples/action-listener/counter/package.json
+++ b/examples/action-listener/counter/package.json
@@ -4,7 +4,7 @@
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.6.0-rc.1",
- "@rtk-incubator/action-listener-middleware": "^0.6.0",
+ "@rtk-incubator/action-listener-middleware": "^0.8.0",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
diff --git a/examples/action-listener/counter/src/components/App/App.tsx b/examples/action-listener/counter/src/components/App/App.tsx
new file mode 100644
index 0000000000..5779032d6d
--- /dev/null
+++ b/examples/action-listener/counter/src/components/App/App.tsx
@@ -0,0 +1,36 @@
+import React, { useEffect } from 'react'
+import { Provider } from 'react-redux'
+import type { Unsubscribe } from '@reduxjs/toolkit'
+import { setupThemeListeners } from '../../services/theme/listeners'
+import { setupCounterListeners } from '../../services/counter/listeners'
+import { ChangeThemeForm } from '../ChangeThemeForm/ChangeThemeForm'
+import { CounterList } from '../CounterList/CounterList'
+import { CreateCounterForm } from '../CreateCounterForm/CreateCounterForm'
+import { store, startAppListening } from '../../store'
+
+
+export function App() {
+ useEffect(() => {
+ const subscriptions: Unsubscribe[] = [
+ setupCounterListeners(startAppListening),
+ setupThemeListeners(startAppListening),
+ ]
+
+ return () => subscriptions.forEach((unsubscribe) => unsubscribe())
+ }, [])
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/examples/action-listener/counter/src/index.tsx b/examples/action-listener/counter/src/index.tsx
index 28724d1316..ededcf300a 100644
--- a/examples/action-listener/counter/src/index.tsx
+++ b/examples/action-listener/counter/src/index.tsx
@@ -1,29 +1,11 @@
-import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
-import { Provider } from 'react-redux'
import { store } from './store'
import { themeActions } from './services/theme/slice'
-import { ChangeThemeForm } from './components/ChangeThemeForm/ChangeThemeForm'
-import { CounterList } from './components/CounterList/CounterList'
-import { CreateCounterForm } from './components/CreateCounterForm/CreateCounterForm'
+import { App } from './components/App/App'
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
store.dispatch(themeActions.changeColorScheme('dark'))
}
-ReactDOM.render(
-
-
-
-
-
-
-
-
-
- ,
- document.getElementById('root')
-)
+ReactDOM.render(, document.getElementById('root'))
diff --git a/examples/action-listener/counter/src/services/counter/listeners.ts b/examples/action-listener/counter/src/services/counter/listeners.ts
index 7d49cc583e..3aa6113493 100644
--- a/examples/action-listener/counter/src/services/counter/listeners.ts
+++ b/examples/action-listener/counter/src/services/counter/listeners.ts
@@ -1,6 +1,6 @@
import { counterActions, counterSelectors } from './slice'
-import { AnyAction, isAllOf, isAnyOf, PayloadAction } from '@reduxjs/toolkit'
-import type { AppListenerApi, AppActionListenerMiddleware } from '../../store'
+import { AnyAction, isAllOf, isAnyOf, PayloadAction, Unsubscribe } from '@reduxjs/toolkit'
+import type { AppListenerEffectAPI, AppStartListening } from '../../store'
function shouldStopAsyncTasksOf(id: string) {
return isAllOf(
@@ -14,7 +14,7 @@ async function onUpdateByPeriodically(
{
payload: { id, delta },
}: ReturnType,
- { dispatch, getState, getOriginalState, condition }: AppListenerApi
+ { dispatch, getState, getOriginalState, condition }: AppListenerEffectAPI
) {
const counter = counterSelectors.selectById(getState(), id)
@@ -44,7 +44,7 @@ async function onUpdateAsync(
{
payload: { id, delta, delayMs },
}: ReturnType,
- { condition, dispatch, getState }: AppListenerApi
+ { condition, dispatch, getState }: AppListenerEffectAPI
) {
const counter = counterSelectors.selectById(getState(), id)
@@ -70,17 +70,15 @@ async function onUpdateAsync(
* }, []);
* ```
*/
-export function setupCounterListeners(
- actionListener: AppActionListenerMiddleware
-) {
+export function setupCounterListeners(startListening: AppStartListening): Unsubscribe {
const subscriptions = [
- actionListener.addListener({
+ startListening({
actionCreator: counterActions.updateByPeriodically,
- listener: onUpdateByPeriodically,
+ effect: onUpdateByPeriodically,
}),
- actionListener.addListener({
+ startListening({
actionCreator: counterActions.updateByAsync,
- listener: onUpdateAsync,
+ effect: onUpdateAsync,
}),
]
diff --git a/examples/action-listener/counter/src/services/theme/listeners.ts b/examples/action-listener/counter/src/services/theme/listeners.ts
index 93864d3e6c..b9906f69d4 100644
--- a/examples/action-listener/counter/src/services/theme/listeners.ts
+++ b/examples/action-listener/counter/src/services/theme/listeners.ts
@@ -1,21 +1,22 @@
import { themeActions } from './slice'
-import type { AppActionListenerMiddleware } from '../../store'
+import type { AppStartListening } from '../../store'
+import { Unsubscribe } from '@reduxjs/toolkit'
function onChangeColorScheme(
action: ReturnType
) {
- if (action.payload === 'light') {
- document.documentElement.classList.remove('dark')
- } else {
- document.documentElement.classList.add('dark')
- }
+ document.documentElement.classList.toggle('dark', action.payload !== 'light')
}
export function setupThemeListeners(
- actionListener: AppActionListenerMiddleware
-) {
- return actionListener.addListener({
- actionCreator: themeActions.changeColorScheme,
- listener: onChangeColorScheme,
- })
+ startListening: AppStartListening
+): Unsubscribe {
+ const listeners = [
+ startListening({
+ actionCreator: themeActions.changeColorScheme,
+ effect: onChangeColorScheme,
+ }),
+ ]
+
+ return () => listeners.forEach((unsubscribe) => unsubscribe())
}
diff --git a/examples/action-listener/counter/src/store.ts b/examples/action-listener/counter/src/store.ts
index dd1a7bd6ab..4c7328299f 100644
--- a/examples/action-listener/counter/src/store.ts
+++ b/examples/action-listener/counter/src/store.ts
@@ -2,15 +2,15 @@ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import { configureStore } from '@reduxjs/toolkit'
import { counterSlice } from './services/counter/slice'
import {
- createActionListenerMiddleware,
- ActionListenerMiddlewareAPI,
- ActionListenerMiddleware,
+ createListenerMiddleware,
+ TypedStartListening,
+ TypedAddListener,
+ ListenerEffectAPI,
+ addListener,
} from '@rtk-incubator/action-listener-middleware'
import { themeSlice } from './services/theme/slice'
-import { setupCounterListeners } from './services/counter/listeners'
-import { setupThemeListeners } from './services/theme/listeners'
-const actionListenerMiddleware = createActionListenerMiddleware({
+const listenerMiddlewareInstance = createListenerMiddleware({
onError: () => console.error,
})
@@ -19,7 +19,7 @@ const store = configureStore({
[counterSlice.name]: counterSlice.reducer,
[themeSlice.name]: themeSlice.reducer,
},
- middleware: (gDM) => gDM().prepend(actionListenerMiddleware),
+ middleware: (gDM) => gDM().prepend(listenerMiddlewareInstance.middleware),
})
export { store }
@@ -29,19 +29,15 @@ export type RootState = ReturnType
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
-export type AppListenerApi = ActionListenerMiddlewareAPI
-export type AppActionListenerMiddleware = ActionListenerMiddleware<
- RootState,
- AppDispatch
->
+export type AppListenerEffectAPI = ListenerEffectAPI
-// Typed version of `actionListenerMiddleware`
-export const appActionListener =
- actionListenerMiddleware as AppActionListenerMiddleware
+export type AppStartListening = TypedStartListening
+export type AppAddListener = TypedAddListener
+
+export const startAppListening =
+ listenerMiddlewareInstance.startListening as AppStartListening
+export const addAppListener = addListener as AppAddListener
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch()
export const useAppSelector: TypedUseSelectorHook = useSelector
-
-setupCounterListeners(appActionListener)
-setupThemeListeners(appActionListener)
diff --git a/yarn.lock b/yarn.lock
index d1cc443d13..563ce0f517 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3673,7 +3673,7 @@ __metadata:
resolution: "@examples-action-listener/counter@workspace:examples/action-listener/counter"
dependencies:
"@reduxjs/toolkit": ^1.6.0-rc.1
- "@rtk-incubator/action-listener-middleware": ^0.6.0
+ "@rtk-incubator/action-listener-middleware": ^0.8.0
"@types/node": ^12.0.0
"@types/react": ^17.0.0
"@types/react-dom": ^17.0.0
@@ -5513,16 +5513,7 @@ __metadata:
languageName: node
linkType: hard
-"@rtk-incubator/action-listener-middleware@npm:^0.6.0":
- version: 0.6.0
- resolution: "@rtk-incubator/action-listener-middleware@npm:0.6.0"
- peerDependencies:
- "@reduxjs/toolkit": ^1.6.0
- checksum: 01e600a9e513f883e4c6d02cbe4565b9691d6b43ebff432a9ad7f4f96d07c3164c3a0c14fde4391e3d3f65e18753e567b67d9645a2af27daba6b0aadd5fa2066
- languageName: node
- linkType: hard
-
-"@rtk-incubator/action-listener-middleware@workspace:packages/action-listener-middleware":
+"@rtk-incubator/action-listener-middleware@^0.8.0, @rtk-incubator/action-listener-middleware@workspace:packages/action-listener-middleware":
version: 0.0.0-use.local
resolution: "@rtk-incubator/action-listener-middleware@workspace:packages/action-listener-middleware"
dependencies: