I'll have to disagree with that, on multiple levels.

Thunks are simply an approach for writing reusable async logic that has access to `dispatch` and `getState`, without being tied to a specific store [0]. While I do think more people would benefit from writing middleware for their own particular use cases, most people just want to have a place where they can fetch some data and dispatch an action containing the result. Thunks make that straightforward. Thunks are also by far the most widely used async middleware across the Redux ecosystem. These are all reasons why we settled on thunks as the default async middleware included in RTK [1]. (It is worth noting that with the advent of `useDispatch` and hooks, you can write some fetching logic directly in a `useEffect` call vs a thunk, but there's still benefits to using thunks in many cases.)

RTK has specific support for thunks in two ways. `configureStore` automatically adds the thunk middleware to the store setup [2], and we have a `createAsyncThunk` API [3] that handles the common pattern of dispatching actions based on the results of a promise.

However, nothing about that requires that you use thunks with RTK. You can still add whatever middleware you want to the store, whether it be sagas, observables, custom middleware, or something else.

> The "redux toolkit" or whatever doesn't help with that, it only reifies questionable practices. Skip it. Write a simple utility for generating actions/types, and then go about your business.

I'm afraid this is entirely wrong.

RTK encodes the best practices recommended in our Style Guide docs page [4], and includes APIs that simplify your Redux logic considerably:

RTK improves your Redux code in many ways:

- `configureStore` lets you set up a Redux store in one line with good defaults built in, including automatically adding the Redux-Thunk middleware, enabling the Redux DevTools Extension, and warning about accidental mutations

- `createSlice` generates action creators and action types for you automatically - all you have to do is write reducers and given them reasonably descriptive names. In addition, it uses Immer internally to let you write "mutating" reducer logic that is safely turned into correct immutable updates, so no more nested spread operators.

- As mentioned, `createAsyncThunk` handles the typical use case of dispatching actions before and after making an async request - just fetch your data and return a promise, and it'll dispatch actions automatically.

- `createEntityAdapter` provides prebuilt reducer logic for typical collection management operations, like `upsertMany`, `addOne`, `removeAll`, etc.

So, RTK _is_ that "simple utility for generating actions", and more. It's an official package from the Redux team (ie, myself and the other maintainers), you can pick and choose which of its APIs you actually use in your app, and you can mix and match which parts of your Redux logic are written with RTK with parts that might still be written with other approaches.

[0] https://blog.isquaredsoftware.com/presentations/workshops/re...

[1] https://blog.isquaredsoftware.com/2020/02/blogged-answers-wh...

[2] https://redux-toolkit.js.org/api/configureStore

[3] https://redux-toolkit.js.org/api/createAsyncThunk

[4] https://redux.js.org/style-guide/style-guide