‫Okay, so let's now set up a fake API
‫on a fake web server
‫and then use that to load the questions data
‫into our application.
‫So this time, we're not going to use a real API,
‫because I created these questions myself,
‫and so then there's no API with that.
‫But I still want to basically pretend
‫that we are loading these questions from somewhere.
‫And so therefore, we can create a fake API
‫using an npm package called json-server.
‫So let's come here to our terminal.
‫Create a new tab, basically, here.
‫So with this, we keep this process here running,
‫so the one that is running our app.
‫And then here, we have another terminal.
‫Just make sure that we are in the correct folder.
‫And then let's do npm install json-server.
‫And in the meantime, I'm going to get some data here
‫from the starter data that I forgot to include
‫at the beginning of this section.
‫So when you copied the files,
‫you probably already got this questions.json.
‫But again, I did forget, actually,
‫to place this file here earlier.
‫So let's come here into react-quiz and paste this file here.
‫Or actually, what I want to do
‫is to create a new folder out here.
‫So let's call this folder data.
‫And please, make the same thing here in your file structure.
‫So creating a new file there,
‫and then let's move this questions.json file in there.
‫Okay, so make sure you have that file in that folder.
‫And in the meantime, this finished running the installation.
‫And now what we need to do next
‫in order to be able to call that package,
‫so to run the json-server command,
‫we need to add a new npm script here to this file.
‫So these npm scripts that we have right here
‫are basically the commands that we write here.
‫So each time that we write npm start, we are able to do that
‫because, here, this start command exists.
‫All right, and so let's now create our own npm script here
‫with the name of server.
‫And so what should happen here, then,
‫is that we want to call,
‫so we want to basically run the json-server package,
‫and we want to watch a certain file.
‫And so that file is going to be our questions data.
‫And actually, let's take a look at that data here.
‫So basically, it is just one object
‫with the questions property.
‫And then that property has one array.
‫And so then the array is our usual array of objects.
‫So each object, then, has a question, the options,
‫the correct one, and the number of points.
‫And so this is the file that we now want to watch,
‫so basically, to create an API from.
‫And so we just do data, which is the folder,
‫and then questions.json.
‫And finally, we also need to specify the port.
‫Let's say 8000.
‫And that should be enough to get us going.
‫So let's do npm run server.
‫So here, we need to run keywords.
‫It's not just npm server, but npm run server.
‫Okay, and so now we should have our API running.
‫But somehow, I see that, here, it's port 3000.
‫So here, it's probably all lowercase.
‫So give that a save.
‫Close that here.
‫So it was running, basically, before at the same URL,
‫so in the same port as our React application.
‫So let's reload that.
‫Let's retry this.
‫And yeah, now it is running on port 8000.
‫And so we can just copy this URL, change this to 8000,
‫and, well, then we should see our data here.
‫But apparently, there was some problem.
‫So let's see.
‫Well, now it thinks that it is already in use.
‫So let's maybe quit our other npm process here as well
‫and then run npm start again.
‫And then here, let's run npm run server.
‫Okay, that's still not working,
‫so we can just change to any other port.
‫So this doesn't really matter.
‫So if, for you, it worked like this,
‫then just go with that one and change the 8000 to 9000.
‫And actually, we also need to then add questions,
‫which is basically the endpoint we are creating here.
‫And it is called questions
‫because that is the name here of this field.
‫So if it was called like this,
‫then here, we would have to add these two as well.
‫So now this no longer works,
‫and our data would be here in this URL.
‫But of course, that doesn't make a lot of sense,
‫so let's just use this.
‫And also, you'll notice
‫that this is actually just the array.
‫So here, we see the array is exactly this one.
‫So let's now grab this URL
‫and then fetch it into our application.
‫So we want to load that data on mount.
‫And so for that, let's use our friend the useEffect hook.
‫And as I mentioned, let's just run it on mount.
‫So here, we want to fetch now from this URL.
‫And here, let's actually not even bother
‫with an async function.
‫But let's just use the then method to handle this promise.
‫So this will give us a response
‫that we need to convert to JSON,
‫which will then, in turn, return another promise.
‫So we chain another then handler there.
‫And so this should then give us our data.
‫For now, let's just log that to the console, then.
‫And also, let's catch a possible error here
‫by also logging it to the console.
‫Let's do console.error here.
‫And just like this.
‫Okay, so let's actually try that.
‫So let's reload, come to our console,
‫and beautiful.
‫Here is our data.
‫But now, of course, we will at one point
‫need to display that data here in the UI.
‫And so for that, we are going to need state.
‫And as you can imagine, we will now use the useReducer hook
‫to create that state.
‫So let's do that.
‫So here, we will get the state object
‫and the dispatch function, remember?
‫And then we use our useReducer hook,
‫which was an edit here to the imports.
‫And here, we passed the initial state,
‫which we don't have yet,
‫but we will create this object in a second.
‫And actually, first, we pass in the reducer function,
‫which we also don't have yet.
‫And so let's create both of them
‫outside, here, of this component.
‫So initialState and the reducer,
‫which will take in, remember, the current state
‫and the action that was dispatched.
‫Okay.
‫And now let's start by creating our initialState.
‫And here, let's create questions,
‫which, by default, will just be an empty array.
‫Now, besides this, what we also want is the loading state,
‫so to tell the user that questions are being fetched.
‫However, this time around, we will do it in a different way.
‫So we will not create the isLoading state as always.
‫But instead, we will this time have a status state.
‫And so this status will basically be a string
‫of the current status of the application
‫that will change throughout time.
‫So in the beginning,
‫our application will be in the loading state.
‫But throughout time,
‫we will be able to be in different states.
‫So let me write them right here immediately.
‫So we can be in loading state.
‫We can be in an error state.
‫We can be in a ready state
‫once the data has arrived and we are ready to start a quiz.
‫We can be in an active state
‫once the quiz is actually running.
‫And we can be in a finished state once the quiz is finished.
‫Okay.
‫And so this is a bit of a nicer way
‫of handling all these different statuses
‫that the application can be in.
‫So instead of having isLoading or isError
‫or isReady or isActive states, we just have the status.
‫And then inside the status,
‫we then tell the application what is currently going on.
‫So this has nothing to do with useReducer.
‫It's just another technique.
‫But anyway, let's now come here to our reducer function.
‫And then let's again set up that switch statement
‫that we already saw earlier.
‫So this is now basically a recipe
‫that you will always follow, which is always the same,
‫so at least the setup here.
‫So we switch the action.type.
‫So we basically want to test for different types.
‫And let's start with the case of dataReceived.
‫So this will be the action that we're going to dispatch
‫right here as soon as we actually have the data,
‫so right here.
‫And actually, let's do that first.
‫So here, we will now no longer log the data to the console.
‫But instead, we will dispatch an action to the reducer.
‫And let's create our common usual event here,
‫so that's simply with the type.
‫And so that's the dataReceived type,
‫which we can also think of, of an event.
‫So basically, it's like, here,
‫we are now creating this dataReceived event,
‫which our reducer will then, basically, respond to.
‫So that's the first part.
‫And now here we also need a payload
‫because we want to actually send some data,
‫so send some information to the reducer
‫so that the reducer can then use this
‫to compute the next state.
‫And so here, that payload will be the data
‫that we just received.
‫Okay.
‫And so here, then, remember,
‫we need to return a new state object.
‫And so we will grab all the current state.
‫And then we will set questions
‫to the data that we just received.
‫So that's action.payload.
‫But what is really great about this
‫is that we can now set this other piece of state
‫that is related to the question or to questions,
‫and that is the status.
‫So the status and the questions, many times,
‫will change at the same time.
‫And so that's why having a reducer is so useful
‫because now we can, here, in the same place,
‫also set the status to ready.
‫So basically, we updated these two state variables,
‫so these two pieces of state,
‫all in one go, in this one dispatch.
‫So just by dispatching this one event right here,
‫we updated both the questions and the status.
‫And so we say that we transitioned to a new state
‫by simply dispatching this simple event here.
‫Okay, but anyway, let's also create, then, our default case.
‫And so here, we will, just like before,
‫throw a new error saying that the action is unknown.
‫So give this a save, and let's see what happens.
‫So we are no longer logging to the console,
‫but we should now have those questions in our state already.
‫So we can't see it on the UI yet,
‫but let's take a look at our dev tools.
‫And yeah.
‫We have our questions in the state,
‫and the status has also successfully been changed to ready.
‫So we transitioned to this new state
‫where we changed these two properties of our state object.
‫So that's working great.
‫And now let's just create another event here, basically,
‫for the case there is an error.
‫So case dataFailed, for example,
‫that's just one possible name.
‫And so here, let's again return the entire state,
‫and then we simply set the status here to error.
‫And so then, later on, we will use,
‫of course, the status to display different things
‫here in our UI, in the JSX.
‫So when there is an error, we will display that error.
‫And if we are ready, so if the status is ready,
‫then we will display the questions.
‫All right, but now let's actually dispatch that action.
‫So the type is, this time, dataFailed.
‫And here, actually, let's not pass in any payload
‫because we're not really interested in the error
‫that we're going to receive.
‫So all we will do is tell our state
‫that now the status is an error.
‫So just to test this,
‫let's quit the process here, where we load the data.
‫So with Control+C, we can finish this.
‫And so now, we can no longer fetch data
‫from that endpoint, of course.
‫And so we see that we get some error already.
‫And also, here, we see that the status has been set
‫to error.
‫So that's also working, but of course,
‫let's go back to having our API work.
‫And so if we load now again,
‫then we have our questions here in the state.
‫Now, okay, so we did a lot of things,
‫so let's just quickly recap all that we did.
‫So we installed the json-server package
‫to create, basically, this fake API.
‫And then we created our npm script,
‫in this case, called server, to then run that package
‫and then watch the file
‫where we actually have this questions data as an array,
‫so this array right here.
‫And so then here, inside our application,
‫we use the useEffect hook to fetch that data
‫on the initial render.
‫Then, to store that data in state,
‫this time, we used the useReducer hook.
‫And so then we created the initial state object
‫and the reducer.
‫So that's pretty standard stuff.
‫So we have the questions array, and we have a status.
‫And of course, as we keep building the application,
‫we will add a lot more information here.
‫So we will add, like, three or four more pieces of state,
‫but for now, we are just working with these two.
‫And so then, as soon as our data is successfully fetched,
‫we dispatch the action here, where we tell our reducer
‫that the type of the action is dataReceived.
‫And then as the payload, we pass in the actual data.
‫And so then our reducer receives that action
‫and handles it right here, in this case,
‫where we then assign the payload,
‫so the data that we received from the API
‫onto the questions array.
‫But that's not all, because at the same time,
‫we now were able to set our status to ready here,
‫all in one go,
‫so just with the call of one dispatch function.
‫Now, the advantage of this reducer is,
‫of course, not really clear yet
‫because we only have these two cases yet
‫and only these two state variables.
‫But it will become really clear and really helpful
‫as we go through this section.