# Listener Middleware and Side Effects — Redux Toolkit / Zustand

Source: https://www.skillbyai.com/en/redux-zustand/a-listener

> React to actions without putting effects in reducers.

## Reactive side effects

`createListenerMiddleware` lets you run effect callbacks in response to actions or state changes: analytics, saving drafts, debounced search, or starting work after another thunk finishes. Register listeners with `startListening({ actionCreator | matcher | predicate, effect })`. The effect receives the action and a `listenerApi` with `getState`, `dispatch`, `delay`, `condition`, `take` and `cancelActiveListeners` for debounce-style logic. It covers many use cases that previously needed redux-saga or redux-observable, with a smaller API.

## Debounced autosave

listener.ts and store wiring.

```typescript
import { createListenerMiddleware } from '@reduxjs/toolkit';

export const listener = createListenerMiddleware();

listener.startListening({
  actionCreator: draftEdited,
  effect: async (action, listenerApi) => {
    listenerApi.cancelActiveListeners(); // cancel earlier pending runs (debounce)
    await listenerApi.delay(800);        // throws if this run gets cancelled
    const draft = (listenerApi.getState() as RootState).editor.draft;
    await fetch('/api/drafts', { method: 'PUT', body: JSON.stringify(draft) });
    listenerApi.dispatch(draftSaved());
  },
});

// store.ts
// middleware: (gDM) => gDM().prepend(listener.middleware)
```

## Keep reducers pure

No fetch calls, timers, random IDs or Date.now() inside reducers. Generate IDs in a `prepare` callback or in the dispatching code, and put effects in thunks or listeners.

**Quiz:** Where should an autosave network call triggered by an action live in RTK?

- [ ] Inside the selector
- [ ] Inside the slice reducer
- [x] In a listener middleware effect or a thunk
- [ ] In initialState

*Answer:* In a listener middleware effect or a thunk. Reducers must stay pure; effects go in middleware.
