Transcript from the "Async Thunks with React Toolkit" Lesson
>> The only thing we haven't really kind of talked about in our kind of fundamentals here is how to make AJAX requests. And there's a bunch of libraries to do that. And like most things, it all depends on how extreme your needs are. If you have very simple needs, Redux Thunk is probably the way to go cuz it's incredibly simple.
[00:00:24] If you're doing really sophisticated things, you might want Redux-Saga or Redux-Observable. The application I used to work on for a few years, was a drag and drop editor for putting together emails. It was fully an application. And we found that we outgrew thunk and needed all of the different debouncing and throttling and different flows that came with our RJS and Redux-Observable.
[00:00:48] But if you're just like, I need to hit an API and put the thing on the page, Redux Thunk is pretty easy. And I'll kinda show you this because Redux is gonna abstract a little bit of, I'm gonna kind of show you just a high level of, if one wanted to write the middleware and you should not use this, you should use the library.
[00:01:07] Right, cuz the library has a bunch of other edge cases that it's dealing with, but if one wanted to write the middleware from earlier in this workshop to deal with this. For every action that flows through, if the type of that action is really a function, call that action and pass in dispatch and let it dispatch another action.
[00:01:25] So, we can say all right, I'm gonna dispatch a AJAX call. And it's gonna be like, cool, that's not a object with a type or anything. And it's like, so why don't I call it and then when it resolves, when we get back when the promise resolves, or we hear back from the API, then we'll dispatch another action.
[00:01:40] This is an oversimplified version. So, basically, Redux Thunk allows you to dispatch functions that will eventually dispatch actions. So you're like, I don't have the data from the API yet. Let me dispatch this function that will get the data from the API. And then it will go dispatch the action once we got everything back.
[00:02:00] Redux Toolkit kinda papers over this. It gives you a lot of other nice things of like, it will dispatch an action when it starts loading. It'll dispatch an action when it's fulfilled. It'll dispatch an action when it errors and stuff along those lines. So it takes care of a lot of the boilerplate for you.
[00:02:14] So let's go ahead and look at that. And so I've got this search over here. And we'll actually do it here. So we can do in our code editor and push it up. Which is I wanna be able to type in some name and then hit Submit and go search for characters within the Star Wars universe.
[00:02:40] Right now this isn't wired up to do anything, so we're going to put it in place ourselves. So I've got most of the initial, this is the chores that we were just talking about. I've got most of the initial slice in place, where we've got an empty array of data, the ability to add stuff, but add what, we haven't hit the API.
[00:03:04] And then, yeah, I need to figure out how to do this asynchronously. You remember createAction from before, we were able to make our own actions? And we used it for that toggle task in the last example. There's another helper called createAsyncThunk, which is a mouthful. But it's very similar, but it's for creating asynchronous actions that eventually will have the data that we need.
[00:03:35] So we'll say, const, I don't know, fetchCharactersFromAPI. We want createAsyncThunk, which first, we're give it the name of the action, just like we did with createAction. And the first argument is, what's the type? And so we'll say it's characters/, I don't know, fetchCharacters. FetchCharacters, sweet. And then it's gonna take an async function.
[00:04:29] We'll say, response = await. We use the fetch API. You could use Axios. You could use whatever. This is just a regular asynchronous function. You can use whatever API or AJAX library you want to use. You can use jQuery's getJSON, if you want to. It doesn't matter to me.
[00:04:49] So we're gonna just fetch, I need to pull in this ENDPOINT real quick. I gotta type that by hand. We'll fetch the ENDPOINT plus whatever the search term was, right? So if they type in D-A, it'll be this API plus D-A, which will search the database for characters that start with letter D-A, which in Star Wars is a thing.
[00:05:41] And then finally, this function will pause until we hear back from the API. It will get the response of the, we can call it result. We'll call it response. And if we look, let's hypothetically, if I go over here, we can see what the shape of the API data is.
[00:06:06] Give it a second. I'll start typing as that comes back. We'll return response. And I believe it's the results key. All right, so you can see results, and it's gonna have a whole bunch of different characters that we want to load into the state. So this is now an action that will dispatch an API call, wait for it, and then it is going to then dispatch action for us under the hood that we can actually use synchronously in our redux state.
[00:06:41] So it's effectively an action creator that supports promises, right? Cuz all of this, once we say, createAsyncThunk, this asynchronous, which is mostly doing a regular fetch request at this point. It's just whatever we return out of this promise will be the payload of the action that is eventually fired.
[00:07:01] I think it'll make a little more sense once we wire this up, we can actually see it in the dev tools as well. So because this is not one of the ones we're making it outside of this reducers object, we do need to add an extra reducer. And I can use builder, but just to show you the other syntax, I'll do it here.
[00:07:26] Which is we'll just say, this fetchCharactersFromAPI.fulfilled, because this is gonna fire off, one, when it starts the request, the pending one. So we can show or hide loading. One when it's fulfilled when we have the data. One if there's an error as well. And here we'll just say, state and action.
[00:07:49] And we'll do state.data, which is where we're storing stuff, if you look at the initial state. And we'll that's the action.payload. All right, let's see if any of this works. We'll go back over here. Open up those tools for the redux ones. [INAUDIBLE], refresh that real quick. I know what I'm missing.
[00:08:38] You can make all the actions you want, you can make all the reducers you want, but if you don't actually put them on to the buttons, then they don't do anything. So we gotta handle change. And here, did we export that one from earlier? Let's see, let's export it.
[00:08:59] And we'll go into fetchCharacters. And now, when they submit the form, we'll do fetchCharactersAPI, with whatever that value was. That's a search term in this case. It's really into capitalizing these slice names, I don't like it. All right, so now with the da. Let's see what's going on here.
[00:09:35] We got dispatch, right? So we'll do, const dispatch. This is a little bit of a PSA for why sometimes binding the action creators does make a lot of sense. Cuz if you just call the function, it'll fire that network request, but you'll never get the promise actually dispatched.
[00:09:55] So we need to dispatch the result of that. So we'll use dispatch. And then we will, As well. All right, third time's a charm. All right, you can see. Let's see if I can configure this so we can actually see the full name. So it starts off by firing an event called characters/fetchCharacters/pending.
[00:10:21] This means we have fired off the network request but we haven't heard back yet. Then, right, we have fulfilled, which has the data in the payload of the whatever characters match, which we then load here as well. And so with the extra reducers, we can also listen to the pending event.
[00:10:40] And we can decide we're gonna show or hide loading as well. Cool, and so what we'll do here is, without really changing much in the way of our actions or anything in the rest of our component, we can throw in, if it's pending, We're gonna set loading to true.
[00:11:11] When it's fulfilled, we'll set loading to false. We'll start out loading as false as well. So now it'll show loading automatically. When it comes back, we will then hide the loading and show the data. Yoda is apparently the only character in the Star Wars universe that has Y-O in this name.
[00:11:43] I just learned that literally right now in front of all of you. So we can basically have the whole life cycle of network requests built in and managed for us by Redux Thunk. Let's just kinda take a look and then we'll do one last exercise together as friends.
[00:11:57] Just to kinda tie this all up a little bit, which is, we create this in the same way that we created actions before. It's again, the first is a string, what is the name of the action that we're creating here? The two distinctions between create Action, where we did that toggle task before, and this one, is, it is an asynchronous function that's gonna eventually give us our payload when the promise resolves.
[00:12:26] And it's also gonna fire off a pending and fulfilled version of the action. So we can manage the lifecycle of when it leaves and when it comes back and if it errored, right? So it's kind of just making an abstraction on things that you could do yourself by hand.
[00:12:39] Normally, if you were gonna do this in a regular React application, you would either in a useEffect, or in a thunk, or something along those lines. You would fire off the action saying, okay, I'm sending it now, I'm have a network request pending. I have started to fetch the characters, right?
[00:12:54] You would wait for the promise to resolve and then you would dispatch another action saying, I've gotten them back, here they are, take down the loading stuff, so on and so forth, right? This is basically encapsulating that lifecycle for you and making it super easy to work with as well.