Our app right now only has one async function. It’s getExchangeRates
and it's found in api.js
. That’s currently being called in a useEffect
hooks inside of ExchangeRate.js. The hook is nice because it runs on first load and then any time our base currencyCode gets changed. In general, I think this is the right way to model API updates such a this one.
However, there are cases we will want our action creators to support asynchronous calls. This is a very common pattern found in legacy redux application, so I think it's worth exploring in depth.
import thunk from "redux-thunk";
// ...
createStore(combineReducers(/* ... */),
applyMiddleware(thunk)
);
Instructor: [0:00] Back in your terminal window, go ahead and type yarn add redux-thunk or npm install. Open up store.js and type import thunk from redux-thunk. We also need to import an additional method from Redux, applyMiddleware. Let's use that as a second argument to createStore. Type applyMiddleware(thunk). We've now set up Redux Thunk.
[0:22] Now, back in exchange rate, let's comment out our useEffect hook, as well as our useState hook. Let's get the currency data with a selector. This one doesn't exist yet, but we can pretend, const currencyData = useSelector(getCurrencyData). We'll go ahead and create that, getCurrencyData. We will get rid of those two imports. We don't need them anymore.
[0:46] Let's go into rates.js and create our get currency data selector. Export const. get currency data equals state, state.rates.currencydata. For our initial state, we'll copy over exactly what was set before and exchange rate.js, a simple object with a key of USD and a value of 1..
[1:10] We have data for a single currency, not quite as glamorous as it was before, but it is all in Redux. It was actually easy to get it in there. Now we need to make our API call. Let's update our change currency code action creator. Instead of returning an object, let's return a function with a single argument of dispatch.
[1:29] Inside of that function body, we can now dispatch our currency code changed action, and here we'll switch the action type to a constant. You can see I had the wrong action type before. It's a little bit confusing to see two functions like this. We're going to change this to a function declaration to make it easier to read.
[1:45] Change const to a function, remove the equal sign and insert a curly brace at the end of the line. Then, in the function body type, return function change currency code thunk with an argument of dispatch. Inside of that, we'll live our dispatch currency code changed action. Now we need to make our API call. At the top of the file type import, get exchange rates from ../API.
[2:10] Then, after the dispatch function in our thunk, type, get exchange rates currency code. Now, this takes a second argument called supported currencies, which is currently defined in exchange rate.js. We'll copy that into this file and export it, hop back into exchange rate and let's import it back in here. Now that we have this in rates, we can use it in our get exchange rates call.
[2:34] When the API call comes back with the rates, we'll dispatch another action. This one will be rates/ratesreceived, and the payload will just be the rates we got back from our API.
[2:45] This action doesn't exist yet in our reducer. Let's add it. Type case 'RATES/RATESRECEIVED' and return {...state, currency data: action.payload}. Save that. Now as I select new currency codes, we make the API call, and they show up in our rate table.
[3:08] When we had a useEffect Hook in charge of making our exchange rates call, it would happen immediately on upload. Our new approach only fires when we change the exchange rate.
[3:17] Open exchangerate.js, and un-comment out the useEffect Hook. Then, remove the currency code from the dependency array. Above the Hook, type const dispatch = useDispatch(). Then, we need to import useDispatch and useEffect at the top of the file.
[3:36] Inside of your useEffect Hook, type dispatch. Then, import the changeCurrencyCode action creator. We'll dispatch changeCurrencyCode with whatever the currency code is on first render.
[3:49] Type dispatch (changeCurrencyCode, currencyCode). Now, we'll update the comment to be more accurate. Now, we have our useEffect Hook being called on first render to populate our exchange rates as soon as the app loads.
[4:03] Let's review what we went over. We introduced a new library called Redux Thunk, which is a Redux middleware that adds support for asynchronous action creators using thunks. A thunk is basically a function that returns another function.
[4:16] We used one of these in changeCurrencyCode, which now returns a function that receives a dispatch function as its argument and calls it both when currencyCode is changed and after our exchange rate call comes back. When those rates are received, our rates reducer stores them for us. We access that at exchangerate.js with the useSelector Hook.
[4:37] Finally, to kick off our exchange rates call on page load, we have this useEffect Hook, which takes no dependencies and only gets called once.