Search code examples
reactjsreduxredux-thunkredux-toolkitthunk

can you clarify the use of thunks in redux toolkit? a few specific questions


Looks like thunk and saga are 2 types of middleware to allow side effects and asyncronous actions in Redux Toolkit. Based on some basic googling, looks like thunk and saga basically serve the same purpose. Without understanding the key differences between the 2 types of middleware and based on some basic googling, I get the impression that historically, thunk has generally been preferred for small to medium size apps whereas saga has generally been preferred for larger apps.

However, Redux Toolkit has included thunk as default middleware for its slice implementation. So it seems like the Redux Toolkit dev team has decided that thunk is a better choice than saga. Am I inferring this rationale correctly? Can you think of a scenario where saga would be a better choice than thunk for a Redux Toolkit implementation (outside of bias based on the level of developer experience with sagas in particular)? Or does the inclusion of thunk as the default indicate that the Redux Toolkit dev team has chosen thunk as the winner between those 2 middleware technologies?

Looks like createAsyncThunk is the main function used with thunks and it's generally used in regards to supporting api integration. Taking a step back, the general purpose of thunk is to "allow side effects and asyncronous actions" but in reality, is the vast majority of thunk implementations in production apps used to specifically support api integration? For example, if I stated in an interview that I had only used thunks for api integration then would that be a reasonable statement if that's the 90%+ use case for thunk usage? Or are there any specific scenarios where you've used thunks in the past which were not specifically for api integration but represent an important use case scenario that you think developers should understand?

Finally, looks like the Redux Toolkit dev team recommends RTK Query for API integration as opposed to thunks these days. So what would you see as the main scenarios, if any, where using thunks would be the recommended approach in a new Redux Toolkit implementation?


Solution

  • I'm a Redux maintainer and creator of Redux Toolkit.

    The short answer to all of the above is "yep!".

    Thunks have always been the default / most common side effect middleware for Redux apps, largely because of their simplicity. That's why RTK includes support for thunks out of the box. it's also worth noting that while "fetch data and dispatch actions based on the result" is probably the most common thunk use case, thunks may contain any logic, sync or async.

    That said, it's true that the majority of "async logic" in most apps is really "fetch this data from an API". That's why we created RTK Query, which completely replaces the need to write any thunks, reducers, effects, or hooks to manage data fetching.

    We've been generally recommending against use of sagas in most cases for years. Sagas are a great power tool, but they're kind of like a chainsaw. There are a few very specific occasions when you actually need that tool, and when you do, you need all the power. But it's not something you need on a daily basis, and we've been especially recommending against the use of sagas for data fetching use cases.

    This is even more true now that RTK Query exists. Additionally, the new RTK "listener" middleware solves the same "reactive logic" use case as sagas, but with a simpler API, smaller bundle size, and better TS support.

    Given that, there's almost no reason to use sagas today.

    I'll paste the last slide from my "Evolution of Async Logic" talk:

    What use case are you trying to solve?

    Data Fetching
    • Use RTK Query as the default approach for data fetching and caching
    • If RTKQ doesn't fully fit for some reason, use createAsyncThunk
    • Only fall back to handwritten thunks if nothing else works
    • Don't use sagas or observables for data fetching!

    Reacting to Actions / State Changes, Async Workflows
    • Use RTK listeners as the default for responding to store updates and writing long-running async workflows
    • Only use sagas / observables if listeners don't solve your use case well enough

    Logic with State Access
    • Use thunks for complex sync and moderate async logic, including access to getState and dispatching multiple actions

    I'd recommend reading through these additional articles, talks, and docs pages I've written: