I wish I had this corporate experience. We focus on finesse, abstractions, witty or beautiful code. I keep being forced to optimise things that we haven't measured, add new lines to places to make the code pretty, rename variables, functions and avoid using Javascript arrays and use the "more performant" sets, etc etc.
All of this at the price of the god damn feature never being able to land and my PR staying in limbo for weeks.
But this is just another end of the spectrum I guess.
I've been on the other side of this. Big company was under the impression they could ultimately save money by switching from an enterprise ERP solution that costed them hundres of thousands of dollars in licences with an inhouse one. The only problem was the ERP was carrying 90% of the company on it's shoulders and this would've been a horribly large task. I worked on it for 2 years with incompentent managers and slow progress. After I left the company they continued for another 2 and then quit that endevour. Wasting a shitload of money (think 10 devs + managers for 4 years...).
HAH! and ironically I read this literally 10 minutes after you posted it :)
dons maintainer hat
<ObligatoryResponse>
We've been generally recommending against use of sagas for years - they're a power tool, and very few apps need that. They're also a bad fit for basic data fetching.
Today, Redux Toolkit's "RTK Query" API solves the data fetching and caching use case, and the RTK "listener" middleware solves the reactive logic use case with a simpler API, smaller bundle size, and better TS support.
I'll use your nice response for an actual question/remark, gotcha! =)
Recently I had a look at the kubeshop-dashboard repo[1] and their use of the RTK Query API[2]. When I write the boilerplate for any SPA nowadays, I usually like to merge any fetching logic with the lib-specific notification/toast-methods, in order to render something to the user about any reached warning- or error-timeouts for each ongoing fetch by default. Meaning:
- every new fetch would start a timer
- after 10secs a warning-notification is shown "a fetch takes longer than expected..."
- and after 30secs the AbortController signals the cancelling of the ongoing fetch and an error-notification is shown "fetch took to long. click to try again."
The implementation of react-query, its "hook-yfied" nature, makes it super easy to wrap it and merge it with the component-lib to create such a thing. I just need to wrap its provided hooks (useQuery, useMutation) with "hook-creators" (I usually call them createQueryHook and createMutationHook) and don't need to dive into any of its implementation specific details.
But createApi, as provided by RTK Query API, makes this quite a bit harder, or so it seems to me at least. How would you wrap createApi to provide such a functionality for every fetch by default?
Hmm. Lenz ( @phryneas in most places) could speak more to some of this, but I don't think RTKQ really supports the idea of "canceling" a fetch in general. Can you give some specifics about what that means in your case?
As for the timers and toasts go, I can think of two possible approaches off the top of my head.
First, you could provide a custom `baseQuery` function [0] that wraps around the built-in `fetchBaseQuery`, does a `Promise.race()` or similar, and then triggers the toasts as needed.
Another could be to use the RTK "listener" middleware [1] to listen for the API's `/pending` actions being dispatched. Each pending action would kick off a listener instance that does similar timer logic, waits for the corresponding `/fulfilled` or `/rejected` action, and shows the toast if necessary .
If you could drop by the `#redux` channel in the Reactiflux Discord [2], or open up a discussion thread in the RTK repo, we could probably try to chat through use cases and offer some more specific suggestions.
> Can you give some specifics about what that means in your case?
react-query has a default behavior to cancel a fetch when the component unmounts (AFAIK), eg. the user changes to another view and the data of the previous view aren't needed anymore. I prefer to only have those fetches pending which are actually needed and seem likely to succeed, as otherwise my SPAs would just add unnecessary load on the API gateway. I specifically had such a case when the backend team was in transition to a microservice architecture, hence the timeouts.
But thanks, will join the discord then after I created a repo to play around.
What's weird is that I still firmly believe that sagas is one of the sanest ways of organizing an application. I built a sort of boilerplate project that shows how I use it[1] but the TL;DR is that I can wrap all of my functionality into nice little sagas and manage the state very easily with lenses. Handling data fetching isn't too complicated either [2] but I'm also not doing any sort of fancy caching in this example.
I'm 1000% with you on this. If you're dealing with a bunch of operations that need to happen in a very specific order, there's really nothing else out there that comes close. I'm able to look at saga code I've written months (or years!) ago and figure out what's going on in a short amount of time without having to jump around.
I used sagas pretty heavily in an app I built to transfer data between Clockify and Toggl, which required that data be fetched/loaded into state in a very specific order[1]. You can't be sagas for clarity.
Yeah, sagas can be useful - not saying they aren't.
But on the other hand, I've seen plenty of codebases and talked to lots of Redux users where sagas turned into an impenetrable spaghetti mess of actions and events going everywhere, and it was impossible to trace what was going on.
There's also a lot of additional boilerplate you need to write to use sagas. Redux's early reputation for "boilerplate" was deserved, and there's a lot of reasons why that happened - patterns shown in the docs, things like action creators and string constants, immutable updates with spread operators, etc. While they weren't _required_, sagas were definitely _a_ contributing factor to that reputation.
We've pushed to erase the "boilerplate" concerns and fix that reputation with Redux Toolkit, and so a part of that has been encouraging people to _not_ use sagas unless absolutely necessary. I wrote up a post a while back on reasons why we opted to focus on thunks instead of sagas in RTK [0], and the "Evolution of Async Logic" talk [1] (which I need to turn into a docs page) covers our recommendations today.
If sagas do work well for you, that's great! But we really do think they _aren't_ the right choice for most Redux apps and users.
Agreed that sagas can turn into spaghetti and probably aren't a great choice for most Redux apps. Just like everything else in this industry, sometimes you should use stuff, sometimes you shouldn't, it depends. I did want to mention that I've been using Redux for over 6 years now and I really appreciate the improvements you and the rest of the contributors have made. Keep up the good work and thanks for being awesome!
In Macedonian we say "ne me boli kur" or the more prevalent "me boli kur" which mean "my dick does not hurt" or the latter more ironic version "my dick hurts".
Hey funny seeing you here! Twoslash is incredible, I'm jealous of some of the stuff you can pull off since you're TS/JS only. You've done an amazing job with it, I've always enjoyed looking through your docs.
well I sort of love to be the guy that asks if there is some other library that binds to redux that I will love, and thus also cause me to feel some sleight love by association for redux?
Well Tucker Carlson also said he used Signal and his messages were leaked by the government so yeah...