Yeah, let's just say that `createAsyncThunk`'s use of TS generics is, uh.... interesting :) The "object field override" generic technique is neat, but also weird at the same time.
Really, just doing `const state = thunkApi.getState() as RootState` is an entirely valid workaround here. Sure, you can argue it's not as "type-safe", but it's got the same net result and it's less clunky.
Just out of curiosity, has anyone looked at our new RTK Query data fetching API for possible usage? The reception for RTKQ has been highly enthusiastic so far, and it's designed to eliminate the need to write _any_ thunks or reducers for data caching scenarios. (Like everything else Redux, you can mix and match whichever works best for a given use case.)
- https://redux-toolkit.js.org/rtk-query/overview
- https://redux.js.org/tutorials/essentials/part-7-rtk-query-b...
First of all - thank you for all the hard work! My team and I are really impressed with what you've built so far.
The company I work for has recently started to adopt RTK and RTKQ. We're working in a legacy React/Redux codebase, and have been evaluating them as core libraries moving forward as we build one of our new features.
One of our other engineers has been leading the charge with learning/applying RTK/RTKQ.. so he has a better feel for it at this point, but I've been following along fairly closely in PRs.. and as the technical lead on our team, I'm responsible for deciding whether or not it's a good fit for us.
As of just a week or so ago, we've pretty much decided to go all in on it.. despite my initial reservations mostly due to worrying that it's just the latest "new kid on the block"
The RTK part I bought into pretty quickly. Having seen a bunch of flavors of Redux code, I especially love the way RTK allows you to write reducers that mutate state directly.. and just really abstracts away a lot of the complexity, providing a means to writing idiomatic Redux code! On the flip side, I am a little worried about how much it hides what Redux really does, as someone who took a while to really understand it myself. It's started to get into Rails territory from a magic standpoint ;)
RTKQ was a bigger leap for me.. my initial impression was that the API seemed a little clunky.. especially the query "builders" part. While I like the way it allows you to inject different API endpoints where they're used, I do fear it will result in some very tight coupling between it and the requests to services. Having said that, the API has grown on me since I first saw it. So maybe it's just a matter of familiarity.
Anyways, there's certainly more feedback I have! And I'd also be the first to admit I'm not totally fluent in all these libraries and concepts.. so not even sure I'm qualified to speak to these things or if this is what you're looking for. But feel free to reach out to me at bcooke@superdraft.io. Would love some feedback in ensuring our team is really using these libraries effectively.
Thanks again for all your hard work!
Appreciate the vote of confidence. To maybe help address your concerns a bit:
I totally agree that RTK itself is a layer of abstraction that does hide _some_ of what you're used to with writing Redux code by hand. In fact, that's the explicit purpose of RTK in the first place :) At the same time, none of the Redux core concepts change. There's still a single store, you're dispatching actions to describe "events that happened", using reducers that produce immutably updated new state values, and using middleware like thunks to run async logic. The goal of RTK is that you're writing less code to do that :) I talked about some of the design history and goals in my "RTK 1.0" announcement post [0]
Probably the biggest common concern is that using Immer for writing immutable updates with mutating syntax is too much "magic". I get that concern, especially because you do _need_ to know that immutability is a critical part of Redux even with RTK. The best answer I have for that is education, which is why I plastered "IMMUTABILITY IS CRITICAL THIS ONLY WORKS BECAUSE OF IMMER" warnings all over our Redux docs tutorials [1], and have a usage guide page specifically on working with Immer [2].
Beyond that, almost all of RTK itself directly maps to Redux usage patterns that existed long before we created RTK [3].
RTK Query is definitely a much larger leap of abstraction. You're no longer thinking in "actions" and "reducers" and "thunks", but rather "endpoints" and "cache lifetimes" and "invalidation". I covered some of this mindset shift in a new RTK Query section of the "Redux Essentials" tutorial [4]. But, even here, RTKQ's React API was directly inspired from other libs like React Query, Apollo, Urql, and SWR. The "API slice / endpoint builder" concept is unique, and I agree those can get a bit lengthy, but there's definitely a lot of useful properties that come out of defining those up front. But, under the hood, it's all still typical Redux logic: dispatching thunks to make requests, a reducer to manage the cache state, plus a custom middleware to manage cache lifetime behavior. Certainly some bits of "clever" code in there (Lenz Weber is a genius!), but no real "magic" per se.
I'd suggest going through those new RTKQ tutorial pages and see if that helps get you more familiar with how it works. For that matter, the "Essentials" and "Fundamentals" tutorials we added last year may also help clarify just what RTK is doing for you as well.
If you'd like to chat more, I and the other Redux maintainers normally hang out in the #redux channel in the Reactiflux Discord [5]. Please come on by and ask questions!
[0] https://blog.isquaredsoftware.com/2019/10/redux-starter-kit-...
[1] https://redux.js.org/tutorials/essentials/part-2-app-structu...
[2] https://redux-toolkit.js.org/usage/immer-reducers
[3] https://redux.js.org/tutorials/fundamentals/part-8-modern-re...
[4] https://redux.js.org/tutorials/essentials/part-7-rtk-query-b...
Regarding RTK Query, we have used it, a little! I'm going to pass this thread along to the teammate of mine (@sangster) who's been really excited about using RTK Query more — he might have some thoughts to share.
Etsy is still on `react-redux` v5, because it's taking a long time to remove our `react-router-redux` dependency. Once we can move to `react-redux` v7 and can use the RTKQ hooks, I'll be working towards encouraging more RTK Query usage.
I know you _can_ use RTKQ without the hooks, but there's a lot to figure out in terms of establishing best practices and how to hook everything in with code splitting. I absolutely want to get there, because it solves a lot of problems for us.
We started out with the same approach as you guys, by introducing Typescript to the company, making it possible to write code in Typescript, and encouraging teams to use it. We had an OKR to convert all of our Coffeescript to Typescript by the end of the year, though, so eventually we had to go with an automated approach to convert the rest of the files, which you can read about here: https://dropbox.tech/frontend/the-great-coffeescript-to-type...
Can you elaborate a bit more about what sorts of type-guards and run-time validation functions you're thinking about? The only type-guards we somewhat generate are the ones Redux Toolkit makes for all of its actions, but aside from that, we only really use type guards when we're interfacing with a 3rd party API or something.
So like, if you've got an endpoint that says it returns
interface Foo {
baz: string
bar: number
}
What happens if the endpoint actually sends you '{"bar":"23"}'
? How do you check to make sure the 'unverified' data is actually what you think it is?Or if the db schema has a nullable column but the typescript type for some reason isn't nullable/optional? Or worse, the db query isn't pulling the fields it should be (eg the db schema changed but the typescript definition didn't).