Our application is fully ready, but it doesn't make a lot of sense to use mock data.
This is why in this video I want to implement a usage of real API.
And for this we will use such service which is called trivia API.
As you can see, I am on the website opentsdb.com and here we have trivia API.
So what is this?
This is an open database which provides an API for different quizzes, which actually means here we
can select the number of questions, the category of questions, and here the difficulty and of course,
do we need multiple choice or just true false.
We need for our quiz multiple choice and here is an important part.
We must select a correct encoding and for us is interested in this URL encoding.
So actually here if I will select everything and click generate URL.
As you can see, I'm getting such URL that we can use.
Let's open it here and as you can see, we are getting here an object with two fields response code
zero.
This is not interesting for us and here are the results.
And this is array of objects.
As you can see, we have here category type difficulty.
Question This is what interesting for us.
Then correct answer and incorrect answers, which actually means here we have exactly the same structure
like we have inside our mock data, which means it will be relatively easy for us to switch to using
our API.
The only difficulty that you can find here is how our question is looking like.
As you can see here, we have this percent symbols, which actually means that we must decode this string.
And just to remind you to decode a string inside JavaScript, we can use function decode component and
just provide inside the string.
As you can see.
Now, our question is looking completely correct, and this is exactly what we must do.
So the first step that we need to do is remove our mock data from our state.
This is why I want to jump inside context quiz.
And here on the top we have our answers and questions.
And actually questions by default will be an empty array.
And here we can remove completely our input, which actually means by default, we didn't load any data
because we want to fetch them from API.
And also our answers will also be an empty array just because we can't really select answers if we don't
have quiz yet.
This is why here I will remove answers and these two properties are empty array and they think that
for sure our application will break.
Now let's check this out.
I'm reloading the page and as you can see, we are getting red stuff.
Why is that?
Because here we are checking our questions from the state.
And here, as you can see, quiz state dot current question index, which actually means we are trying
to select a question by index, but we have an empty array and of course everything breaks.
To avoid this, we need one more condition inside our quiz component.
So let's jump here inside our quiz.
And as you can see here, we have a part where we are rendering our results.
This is completely fine.
And here is a part where we are rendering our quiz.
So actually here we need one more case.
We need to check that our quiz state dot questions actually is not empty.
This is why here I will write length bigger than zero.
And in this case it should work fine because we won't render anything here until we are getting some
data.
Let's reload our page.
As you can see, we just get an empty background without anything.
And this is totally fine.
We don't render anything.
And then when we are getting our API response, we will fill our quiz and everything will be rendered
automatically.
So now it's time to fetch some data from the API.
The question is how we can do it inside React.
And for this we have a special hook because we can't just really call a fetch method inside our component.
It won't work because the fetching data is a asynchronous process and it should be correctly binded
with our fetching of data.
This is why we have an additional hook inside react exactly for side effects and actually working with
API is a side effect.
So what I want to write here is useeffect and as you can see, we simply call it and pass inside the
function.
And here as a second parameter, I am setting an empty array, which actually means we are writing this
code directly inside component on the root level.
And here I can console.log, for example on initialize.
And it means that here we will call this method only once on initialize.
Let's reload the page.
As you can see here in console, I am getting console.log on initialize and actually by default useeffect
is being triggered after every render of our component.
But when we provide here as a second parameter an empty array, it will be triggered only once because
we don't have any dependencies.
And this is exactly what we want because we want to fetch data only once on initialize now.
Overhand can write inside our fetch, but for this we need our API URL.
So here I want to create an API url and paste inside this code from opentsdb.
So actually you can simply jump here, generate a URL and use it.
The only important part here is to select correct end code.
Now let's try to fetch this API.
And for this we can simply use a fetch method from plain JavaScript.
So here I want to write fetch and inside we are passing our API URL that we want to fetch.
Now we need here then and we are getting our response and we want to read the Json from our response.
And after this we can make one more then with data inside.
So let's console.log what we are getting.
So here I am writing data, comma, data, and this means that we will fetch some data from API by this
URL.
Let's check this out.
I'm reloading the page and here is our response.
So everything is fine.
You can see in network when we filter by XHR that this was our request and this is our answer with results.
And as you can see, here are our results.
And when we open a single object we have here, first of all, a question, then incorrect answers and
correct answer, which actually means we can directly update our questions inside the state and we can
do it in exactly the same way like we did previously by using dispatch, because actually this means
that we want to notify our state that something was changed in our case, that we fetched our questions.
This is why here we can actually use dispatch and provide insight.
First of all, type, for example, let's name it loaded questions.
And here we need payload because we must provide this data inside.
And first, actually data is not interesting.
We want to provide an array.
This is why I will write here.
Data dot results and results contains inside the array of our objects.
Now we need to react inside our reducer for this type.
This is why I'm jumping inside context quiz.
And here we need to provide a new case.
So here after restart we can create new case and name it Loaded Questions.
So what we want to do now, we want to return here, first of all, our spreaded state.
And now we want to overwrite, first of all questions with our action dot payload, because this is
the array of questions that we got from API.
And secondly, we must provide here our answers for the first question.
This is why here we can say shuffle answers and we must provide a first question here.
And in our case it will be action dot payload and here is zero.
Now let's check if it's working.
So I'm reloading the page and we are getting errors.
Question Incorrect answers is not iterable, so let's check what we are getting at all.
So inside this case I will just provide a console log loaded questions and here we are interested first
of all in our state and secondly in our action.
Let's reload the page and here what we are getting.
If I will scroll on the top we have here loaded questions and here is our type.
So type is fine.
And inside payload we have our elements.
As you can see here, we have a problem with naming.
So our data in front end is question dot incorrect answers, which is camelcase.
As you can see here, everything is with underscore.
For example, this incorrect answers.
And this is the first problem.
The second problem is that here, everywhere we have this percent symbol and we need to parse this information,
which actually means that we must normalize this data and we can do it with some additional method.
For example, let's create it inside our helpers.
So what I want to do here is jump inside helpers and here we can create a new method to normalize questions
from API.
This is why here I will name it normalize questions and we are getting here backend questions which
is actually an array.
Now what we want to do inside, we simply want to map this backend questions.
So backend questions, dot map and here we are getting each question.
And now for each question we want to return correct information.
So here we want to return the object and the first property here will be correct answer And here we
actually need to decode our correct answer because it is not in correct format.
This is why here I will just write the code you write component and inside we are passing backend question
and here will be our correct answer.
But it must be with underscore.
The next thing here is our question itself.
So here is question and we also need to put it inside the code component and it will be back in question
Dot question And the last thing that we need is our incorrect answers.
But this is an array.
This is why here, before we must normalize the array, this is why here we have our incorrect answers
and we want to map through our backend question.
Dot incorrect answer.
But here it will be with underscore.
And now here we are using our map.
And here inside, we're getting our incorrect answer because we are getting every element of the array.
And now for every element, we want to call the code component and provide inside our incorrect answer.
So actually, as you can see, we are getting exactly the same stuff again and again just to normalize
our data to correct format.
And we are getting here three properties just like we used before.
This is correct answer question and incorrect answers as an array.
Now let's use this function and the correct place to use it is inside our context because actually here
we are writing this information inside our state.
So what we want to do here, instead of console.log, we can create a new property, normalized questions.
And here we need D because this is a variable.
And now here I want to call our function normalized questions and we are passing inside our action dot
payload, which is the array of our backend questions.
Now here on the top we must check that we have our normalized question function.
Here it is from our helpers.
So here we can now use not just questions but our normalized questions and we also need to provide different
information inside our answers.
This is why here, inside shuffle answers, I'm providing normalized questions and here we need to take
our first question.
This is why it is zero.
Let's check this out.
I am reloading the page and as you can see, everything is working.
So actually our quiz is rendered but with data from API.
So as you can see, here is the question from anime.
And here we need to answer something.
And actually our quiz is working exactly in the same way without any changes.
We simply used an API and filled our state in the correct format, which actually means we can fill
our state from any source, for example from mock data, from API, from WebSockets, and it will work
in any case.
So let's go through steps once again, what we did, first of all here on Initialize, we have empty
questions and empty answers, which is completely valid.
Now inside our quiz, we have this use effect and actually it is triggered once.
This is why here is empty array.
And now inside fetch we fetch data.
And after this we dispatched loaded questions just to notify our state that we fetch some data and inside
our state we normalized our data from backend and put them inside state.
But now I'm thinking about one problem that will for sure happen inside our application with this empty
array.
The main problem with this code that it is happening only once, which actually means I think that our
restart of our quiz won't work.
Let's check this out.
I'm hitting next question and I'm selecting something.
And again and again, here we are coming to the next because we have ten questions and now we have our
completion of the quiz.
Now when I'm hitting restart button, as you can see, our screen is completely gray and actually we
didn't fetch anything.
Why it is happening because this logic is happening only once and when we are hitting restart, we are
cleaning our state completely, which actually means this logic is not correct.
We need to remove here our empty array and in this case we will trigger this use effect after every
render, which is obviously bad.
To prevent this, we can simply write here additional if condition.
For example quiz state dot questions should be an empty array.
So actually if here the length is bigger than zero then we will simply return and don't do any fetch.
And after hitting restart our questions array will be empty and this logic will be triggered again.
Let's check this.
I'm reloading the page.
Now we fetch some data I'm hitting next.
Again, we are on the result page and we are hitting restart and in this case we refreshed our questions
again.
This is why our quiz is working correctly.