So let's fetch ingredients asynchronously.
I'll do that in the burger builder file in the actions folder where we have our action creators. I'll
add a new action creator
so I'll export a new const and I'll name it fetchIngredients or maybe better name, initIngredients
because we want to do this initially to load the ingredients we can use in the burger builder.
I don't expect any arguments on this function and I want to of course return an action ultimately, though
to be precise
I want to return a function here where I receive the dispatch function which I then can use in this
function body
and this is available, the syntax due to redux-thunk
which allows me to use my action creators like this.
Now in here, I can execute async code and dispatch a new action whenever I'm done,
so I actually need a second action creator which I'll export to though theoretically, I only use it internally
in this file, I'll name this action creator setIngredients. Here,
I expect to get ingredients as an argument and here, I will just return an action I want to dispatch.
Now for that, I need an action type
so let's head over to action types and let's add a new action type here,
I'll name it SET_INGREDIENTS and as often or as always,
I'll use this as the string identifier too. So SET_INGREDIENTS, that is the identifier
I'll listen to it in my reducer later.
And with that added, I can go back to the burger builder action file and in the setIngredients action
creator, I want to return an object where the type is actionTypes.setIngredients, just like that
and of course, I'll need to pass a payload, I'll name the property ingredients and that name is totally up to you.
The value is not, the value should be our function argument
which here is also named ingredients,
this one. With that, we get the synchronous action creator,
that is the action I eventually want to dispatch once the async code in initIngredients is done.
Let's head over to the burger builder container to fetch the async code we want to execute, this thing
here.
So I'll just cut it out of the componentDidMount function there and I'll put it into my burger builder
file in the actions folder. Here I want to return to axios and for that, I of course need to be able
to access axios. Now in the burger builder component, we imported axios from axios orders, we don't need that
anymore in the burger builder
so I can cut it from there and also move that import to the burger builder action file. There,
I need to reach out to axios orders,
I need to check if my path is correct, it actually is
so that's all right
and now we can reach out to axios in this file too. Here, the path to firebase should still be correct
but then of course when we get the response, I won't call this.setState and I won't do it for getting
an error.
Instead here, I want to dispatch my setIngredients action creator
so here, I'll execute this as a function and of course, I will dispatch response data here on an axios
response, the data property holds the data which will be the javascript object we want to use.
Now when an error occurs, we probably also want to handle that, in the burger builder container,
we have that error state, we have the loading state and all these things were used here
so I can get rid of error and loading in my burger builder now because I won't manage these state fields
here in that file anymore.
Now loading was only used to show a spinner in the order summary in case we're still loading,
this however shouldn't be required here anymore because we're not doing anything asynchronous when viewing
the modal, when viewing the order summary
therefore. What is important though is the order, here
we set our burger equal to ingredients can't be loaded if we have an error
and to a spinner if we don't
and we actually set it to a real burger builder
if props have been loaded.
So we definitely need to set this error, though not on a state anymore,
we want to pass it with props.
So for that, I need to handle this error as part of my redux state, for that, I'll go to my burger builder
reducer
and here, I'll first of all set ingredients to null initially because now we're fetching them from the web
again and they should be null until they were fetched,
that is all that's required to make sure that this check here in the burger builder fails
if we don't have ingredients yet so that we do display a spinner instead.
But I also need to add a new state to my burger builder state, I'll name it
error and here, I'll set this to false
initially, I want to set it to true though if our loading does fail. With that added, we need one more
action though,
back to the burger builder file in the actions folder, we dispatch an action if we got ingredients that's
great but we also need to dispatch an action
if that fails so that we can adjust our error state in the redux state. So I'll add a new action type
and I'll name it FETCH_INGREDIENTS_FAILED and use the same name as the string identifier
as always and then I'll add an action creator here.
We not only have setIngredients, I also want to have fetchIngredientsFailed here,
I won't get an error message so I don't need to accept any argument,
I just want to return a javascript object here where the type is actionTypes and then FETCH_INGREDIENTS_
FAILED, like this
and this is the action I actually want to dispatch when it fails.
So I'll dispatch something in the error case too, I'll dispatch fetchIngredientsFailed and don't pass
any arguments.
So with that I'm handling both cases and
now of course, we need to handle these new actions in the reducer and also make sure that we connect
our burger builder correctly to these new things like for example, the error state and one thing I just
noticed, we also still need axios in the burger builder container for this withErrorHandler
higher order component.
So I'll quickly grab that axios import from the burger builder action file again and re-add it to the
burger builder container.
Now one important note about that, we can still handle the errors with our higher order component here
because we're using an axios instance, so no matter if we do send the request from another place in the app
like our async action creator,
we can still handle it with the same axios instance which we're passing to the higher order component to
show our error modal
which of course is what we want to do
still, we want to have this central error handling place.
Now with all that in place though, our application wouldn't work as expected because now we need to work
on the reducer to handle these new action types
we have for fetching ingredients.
Right now, it's always spinning.