Quiz Game | React, Redux Saga, Redux Toolkit & Tailwind CSS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Nice tuto :) you're a perfect cosplay for Shoto Todoroki

👍︎︎ 2 👤︎︎ u/volta_werner 📅︎︎ Mar 06 2021 🗫︎ replies
Captions
hello youtube raul here in today's video we're gonna build a quiz game using react redux redux saga vdox toolkit and the open trivia database let me first show you how this game is gonna work so the first screen is gonna be an input where you can type your name then you press start game we get a short loading and there was also a button on which you could click to cancel the game now here at the top we have a timer which is set to 60 seconds on the right corner we have the number of questions left to answer on the left we have our score here in the center we have the questions and for this i only used true and false questions so we have two and false and at the bottom we have the quiz the quit game button so if we press and answer the questions you can see i answered two questions correctly and we have three questions out of ten so let's finish all of them and on the end screen we have game over we have our score so i answered five questions correctly out of ten we have a try again button which will take us to the first screen and here we have a table which contains the questions our answers and if they are colored in red then that means we had a false answer or a wrong answer actually if they are colored green that means our answer was correct so these three that one and the second last one were correct so what we are going to use for this we are going to use the open trivia database which is a public api for which you can you can get trivia questions you can set it up in different ways so here you have a some inputs some selects actually to get the exact url that you need for me i'm just gonna get the type as true and false questions the number of questions is going to be 10 then i'm gonna click generate api url and we're gonna get this api url if you want to set your project up differently you can but make sure to also add the changes so for example if you want 20 questions there are going to be places in your app where you will have to change some stuff from what i will do or actually some values okay we're going to keep this open because we're gonna need this url later then we're gonna use redux saga so if you want an introduction to redux saga i have two videos with the basics and the advanced concepts of redux saga links will be in the description below also for our redux logic we're gonna use the redux toolkit again link to the whole playlist for everything you need to know about redux toolkit will be in the description below and as a first in my video tutorials i will use tailwind css at the end of the video to style the application like you saw in the demo as a quick mention i just passed 100 subscribers on youtube thank you everyone who subscribed if you didn't make sure to subscribe leave a comment to this video if you enjoyed it and also like it this will motivate me to make more videos like this and you have helped me out a lot so thank you all now let's get started jumping into vs code i have a new app created with create react app from which i deleted the unnecessary files i just left app.js i removed the boilerplate code just had a have a div with high in it then we have an empty index.css we're gonna need this later to add tailwind so i'm gonna show you how to do that in the second part of the video and on index.js in which i include the index.css get the app and render it before we do anything else let's install the libraries that we need so i'm gonna run npm install dash dash save react redux redux at redux js slash toolkit and also redux saga for the moment we're gonna see how we can add tailwind css when we actually need it so let's just run these for the moment now we're gonna wait for these to finish now that these are finished let's run mpm start and let's get started the first thing we're going to do is create a new form folder for our redux store in this folder i'm going to create an index.js and here we are going to create the store in a moment another file that i'm gonna create is the root reducer so i'm just gonna call it reducer.js and the third one is gonna be a saga.js so these three are the main files that we need for our store the reducer is going to contain our root reducer the saga.js is going to contain our root saga and in index we're going to create the store let's create the reducer first so here we are going to import combine reducers from redux later we are going to get the reducers that we create and for the moment let's just export default combine reducers and put an empty object into in there react is going to complain a little bit and we're going to get a warning in the console but we don't care about that for now in redux saga so in the root saga let's import all from redux saga slash effects at the end we are going to export default a generator function which is going to have a yield all and inside this all for the moment we're gonna have an empty array and in this array we are going to put our our sagas after we create them and the last part of our story is to actually create the store so let's import configure store from at redux js slash toolkit then let's import the default export from redux saga and call it read create saga middleware from redux saga then i'm gonna create a new constant called saga middleware and it's going to be a call to create saga middleware next let's create a constant called store and it's going to be a call to configure store and it's going to have a configuration object this configuration object needs a few parameters first of all is going to be the reducer so i'm going to import the root reducer from dot slash reducer i'm also going to import the root saga from dot slash saga so we can run it later and now let's continue with the configure store so the reducer key is gonna get the root reducer and now we have to add our saga middleware so to the middleware key we're gonna use the functional form for this we're gonna get the default middleware and we're gonna call it we're gonna pass an configuration object to it with tank set to false because we don't want redux tank in this one and to the return of this function we are going to concatenate so dot concat the saga middleware so this way you can replace the thunk middleware which is added by default by a redux toolkit with the saga middleware the last two things we have to do is run saga middleware dot run and pass the root saga to it and export default store now let's link this store in our index.js file so i'm gonna import the provider from react redux and also gonna import the store from the store folder and the index now i'm gonna wrap the app with provider pass the store and put the end tag after the app okay now if we save if i open the dev tools and go to the redux tab i should also refresh the page we get the redux dev tools so this way we know that our store was linked to our application because the redux toolkit adds the redux dev tools by default so we don't have to worry next let's set up the main pages of our application we're just gonna leave them blank but let's have them created for when we need them so i'm gonna create a new folder called pages and inside of these pages i'm going to put all my pages i'm not going to create separate folders for them because i'm just going to have these pages so it's not really complicated i won't need components for each page so i'm gonna have a main page i'm gonna have a start game page dot js then um we're gonna have a fetching page so this will be the page that's actually shown when the questions are fetched then the next one is going to be the game page so the page that shows our questions and the last one is the end game page the fun part about this quiz game that i'm building is that we will put all the logic inside our redux saga so we won't use logic inside of our pages we'll just use them to display some data now going into the main page let's create our general component so i'm gonna use a shortcut from an extension called es7 this es7 react redux graphql snippet so i'm gonna use this extension to generate my components if you have it installed you will just have to type rafce and it will create a functional component for you for the moment i'm just gonna say main page inside this div let's go into app js and add this main page so import main page from dot slash pages main page and let's put it replacing our div i'm also gonna just have a react fragment here because we don't actually need a div okay and now you can see we have main page here now let's do the same for our other pages in the start game rafce enter and we get the start game page i'm just gonna say start game here and save it now the fetching page the same fetch then in the game page we're gonna say game we will add some more data in these as we go along with the app so and now that i have created all of these pages let's import them all into mainpage.js because this is where we will use a switch statement to display our app's content so import start game from start game page import game from game page import fetching from fetching page and import and game from the end game page great now i won't be displaying these for the moment we will add them in a switch statement when we get the condition from for our switch inside of our redux store so that will be in a moment let's first go and create our first part of the redux store so our first slice i'm gonna create a new folder here called slices and the first slice we're gonna create is called gameinit.js inside of this game init we are going to import create slice from at redux js toolkit then we are going to create a constant called initial state which is going to be an object in this object we are gonna put the stage which is gonna be which part of our application we are uh displaying at the moment for the moment i'm just gonna put one in here we're gonna create some constants for these so we don't have to get numbers okay and the second part of the state i want to add for now is the username for the moment it's going to be an empty string this username is going to be what we type in the input at the start now as i told you i want to have some constants defined for these because i don't want them to i don't want to remember the numbers but we can do this without constants 2 if we want i prefer the constant way because it's easier for me to remember so i'm gonna create a utils folder in this utils folder i'm gonna create a constant for constants.js file and inside of this constant.js i'm going to export a constant called start game all caps and it's going to be start game as a stain so we're going to do this for all of them so export const game is gonna be game then export const fetching game is gonna be fetching game i do this just because i don't want to remember the numbers this way we will have all of them named endgame and endgame now going back to our init slice i'm gonna import all of them as pages from utils folder and constants and now instead of stage one let's call it stages dot start game so this will be the first page that we display now let's create our slice so const game init slice is gonna be create slice and then we're gonna have the name for it game state i'm gonna call it the game stick because this actually let's also give it the same name so we're gonna have the game state and also the same name this will be the first part of the names of the actions that are gonna be dispatched from this state then we're gonna pass the initial state and then we're gonna create the reducers object in this reducer object we're gonna put all our reducers for this slice now at the end let's create our export so we're gonna export const it's gonna be an empty object so we're gonna destructure the game stand it dot actions so these are gonna be named exports and then at the end i'm gonna export default the gamestate.reducer this way we have our reducer exported default and here we will put all our created actions so we can export them and dispatch them from everywhere in our app now let's add the reducer to our root reducer so i'm gonna import game state from slices game init and here we're gonna just pass the game state now if we open the redux dev tools i'm gonna also put them here at the bottom and make it a little bigger if i refresh the app and we look at the state now we have the game state with the stage and the username okay let's create our first reducer the first reducer we are going to create is the start game reducer it's gone it's gonna get the state and the action and inside of it we are going to set the state.username to be equal to action.payload.username so we're going to expect the username key inside the payload and also set the state.stage to be equal to stages dot fetch game so we're gonna move our game to the next stage if the state will be stage dot start game we will display the start game page if the stage is fetching game we will display the fetching game page let's export this action so we can dispatch it so i'm gonna just put it inside of here now let's go to our start game page and inside of this start game page we are going to add the input and the button that so we can dispatch the action so let's first import use state from react let's create a new constant called username and set username as a call to use state and the initial value is going to be an empty string then inside of the div i'm gonna have an input with the value of username the on change is gonna be we're gonna get the event and set the username to event.target.value also i'm going to put a placeholder for now so we know what it is i'm just going to call it your name and close the input and then a button with an on click handler which is gonna be a call to start game handler it's gonna be a function which we're gonna create in a moment and the text on this button is going to be start game okay now it too and ever because it doesn't know what start game handler is so let's create start game handler and inside of this start game handler we will have to dispatch the start game action let's import that action it's gonna be import from the store slices game init from here we will get our start game action we also have to get the use dispatch hook from react redux we're gonna initialize this hook into a constant called dispatch and it's gonna be a call to use this patch and now using this dispatch constant we can dispatch some actions so we're gonna dispatch the start game and as a parameter we're gonna give it an object with the username that we have from the input and this is it for our start game component now that we have something to show inside of our main page let's go into the main page and display these pages conditionally so i'm gonna import again all as stages from the utils folder from the constants and now let's get the stage from the redux store so to do that i'm gonna also import use selector from react redux and let's get the constant current stage is gonna be use cell selector we're gonna get the state and return state dot game state dot stage so this is this constant right here that we have in our redux store which contains the start game at the moment now let's create a an oled which is gonna be called displayed page and now inside of a switch statement we are going to switch the current page and in case we have stages dot start game then display page is gonna be start game page and we are going to break here the next one is gonna be stages dot fetching game and here displayed page is gonna be the fetching page and again break the next one is gonna be stages dot game and displayed page is gonna be oh it's not two dots here it's an equal my bad and we're gonna have the game and the last one is gonna be stages dot endgame in which the displayed page is gonna be equal to endgame and inside of the default case we are just gonna break so we won't do anything there and now instead of just displaying this text right here we are going to display the displayed page again i'm going to put it inside of react fragment because we don't need the div at the moment okay now if i refresh the page we cannot get the state so let's see what's wrong with that okay so it was just a miss type here it was supposed to be state dot game state not game stage now if i refresh we see our start game page right here and if i type something inside the input and press start game we get our game state start game action dispatch and if we look at it it has the username payload now let's continue and create our first saga inside of this project so let's create another folder called saga inside of this we're gonna create a game init file again because inside of this we are going to put all of our saga actions for this game in it slice let's first create a basic saga so we're gonna import all from redux saga slash effects then at the end we are gonna export default of generator function and inside of this generator function we are going to yield all and just leave it like this for the moment we are going to change it up a little bit later inside of this game init saga we are going to export default a generator function and let's call it start game saga just so we know what this means and inside of this we're gonna put an infinite loop and inside of this infinite loop we are going to yield and now we have to we will have to get some actions so first let's import the take effect from redux saga effects and also let's import the start game action from the slice so let's go into the slices game init and from this we are going to get the start game action and now we are going to yield take and here we will wait for the start game action so to get the action type we get the start game action and the type property of that action and whenever this action happens we will fork a thread which will fetch the questions from the open trivia database so let's yield fork i'm also gonna import the fork from redux saga and this fork will be a fork to fetch questions saka which we haven't created so let's do that so it doesn't go whenever it's gonna be a generator function which is gonna be called fetch question saga and for the moment let's just leave it blank now let's import this start game saga into our root saga so import start game from saga gaming saga and let's call it inside of our all start game just to see if it works let's put a console log here and do fetch questions now let's refresh the page and if i type something into the input press start game and look inside our console we will see that fetch question is console logged so this function will be called inside of this function we will make the call to our api to fetch the questions before we go further let's fix this warning that we got right here so let's go back into the main page because i forgot to add the breaks for the last two cases so let's add those really quick now if i refresh i'm just gonna get a warning in the saga.js that it doesn't like an anonymous expert so we can fix that really quick by giving it a root saga name and it just says that the game init doesn't have a yield so this fetch question saga but that will be fixed in a moment so let's go further let's use the try catch block so we're gonna catch the error inside of the tripod we are going to call the function that will get our data and in the error part we are going to handle what happens when when the data fetching throws an error so first before we put anything inside the try let's create another file inside of our utils folder we will call this api.js and inside of this api.js we will have to make our function for the api call so i'm gonna go back to this open the trivia database and get this url i'm gonna store it into a constant and then i'm gonna export constant fetch quiz from api and inside of this function we are going to return a fetch and we are going to fetch the api url then we're gonna chain a dot then we're gonna get the response and return response dot json and to this dot then we are going to again chain another dot then and get the questions and return the questions dot results so our questions that we get from the api will be in this results key right here let's also catch the error here so if a network is strong and do a promise dot reject with the error this will this rejected promise will be caught in this catch block right here and handled next let's make the call from our fetch question saga to the api so for this we are going to import put and call from redux saga effects we're gonna use them to call a function and dispatch actions first we are going to make the call to the api so we're gonna create a new constant called data we're going to yield call and in this call we have to put our api function that we created before so let's import it from the utils folder and api and here we we're gonna get the fetch quiz from api and we are gonna call this fetch quiz from api we don't have to pass any parameters so that's why call has only one parameter okay and let's console log the data to see what we receive let's go to the app i'm gonna refresh and type something in the input press start game and we get an array of objects this array of objects contains some details about the question like the category the correct answer the difficulty the incorrect answers this is an array because there are also the possibility to have multiple choice questions so you those will be an array of items this is just an array with one item the question and the type we just requested to him false questions so the type will be boolean for all but you could make a game with true and false and also questions that have multiple choice answers now i'm gonna delete this console log and let's create a new slice for our game that will handle all the questions part so we're gonna have a new file called game dot slice dot js or actually i named one without slice so let's just call it game.js in this one again we are going to import create slice from at redux js toolkit then we're gonna create the initial state as an object with a questions key that is an array an error which is gonna be null at the start the score which is also going to be null at the start and the current question index so this way our saga will know exactly at what question we are we want won't use these at the beginning but we will need them later okay now let's create our slice so quiz slice is gonna be create slice the name is going to be quiz then we're gonna pass the initial state and then the reducers here we will need two reducers fetch questions success which is gonna get the state and the action i'm gonna leave it blank for the moment and the fetch questions fail reducer again it's gonna get the state and the action okay so these two reducers are what we are going to use one of them when the questions are fetched successfully and the other one when the when there is an error fetching the questions now at the end let's export as named exports fetch questions success and fetch questions fail as quiz slice dot actions and export default the quiz slice reducer okay before i forget let's just add the quiz reducer to to the root reducer because i always forget to do this so i'm not gonna do it this time and let's add it as quiz now if i okay we have an error i forgot to add the cons there it's supposed to be export const okay like this if i refresh and go into the redux store in the state we also we have our quiz state right now let's quickly create these reducers so in case we have the fetch questions success we are going to set the state dot questions to be equal to action dot payload next we are going to set the state dot score to be zero so this way we will always have a initial score of zero when the questions are fetched successfully state dot current question index is again going to be zero so we'll select the first question and that's about it for now next in the fetch questions fail we'll just set the state dot error to be equal to action dot payload that means we are going to have to send a message in our payload that we want stored in our error handler okay now let's go to the game init saga and here in the try part of the block we are going to yield put and now we have to get that action that we created so we're gonna import from the slices game we are going to get the fetch questions success and fetch questions fail and here we are going to put fetch questions success with the data that we received that array that we received and in case of an error we are going to yield put and fetch questions fail and here i'm just gonna type a message manually because i don't like the errors received from the open trivia double so i'm gonna type there was an error fetching the questions okay so this is it now if i refresh the page type something start the game now in our you can see when the quiz fetch success when the quiz fetch question success action is dispatched we get an array of questions we also get the score of zero and the current question index set to null okay but our game state doesn't change when the questions are fetched successfully so you can see we still have this fetch message right here which is the fetching page the page that should be displayed with the spinner when the questions are being fetched we don't want that we need our game to jump to the third page of this which is the game page in which we will display the questions so let's do that we're going into the game in its slice and here we need to add some extra reducers so we need to handle some actions that were defined in other slices because normally your reducer handles actions that are defined in this slice but we can handle fetch questions fail and fetch questions success that were defined in the games game slice for this we have the extra reducers key in the create slice which receives a builder and on this builder we can do builder dot add case and here in this case we can tell what our slice or our state should be changed if we get actions from other parts of our application so we're gonna do fetch questions success and again we're going to have a function which receives the state and the action and here we're just going to set the state dot stage to be equal to stages dot game okay and let's chain real quick another add case and we're gonna handle the fetch questions fail again state action and here we are going to set the state dot stage to be equal to start game so in case we have an error fetching the questions we want our game to be pushed to the initial state so our user can try to start the game again so we won't be stuck in this fetching place where we can't get out actually we don't need the actions right here because we won't get anything in the payload in for this ex these extra reducers okay now let's see if that works refresh name and now when the fetch question success is dispatch you can see our stage changes from fetching game to game and we can see the game page right here and the questions as before now let's create the fetching page so what's gonna have what we can do on the fetching page on this page for the moment we are going to have a p tag that's gonna say loading we are gonna style this later and create a nice spinner and on top of this we are going to have a button which is gonna say cancel and for this we're gonna have an on click handler and when we click this button so if the user manages to click the cancel button while the quiz is being fetched then we are going to cancel the fetching and return him to the start page maybe he changed his mind that doesn't want to play anymore let's first first let me clean up all the open files now let's go to our game init slice and here we need to create a new reducer for when the user presses the cancel button so we're gonna call it cancel game it's gonna get the state and the action inside of this we are going to set the state dot stage to be equal to stages dot start game and this is it now let's export this so export the cancel game and in our fetch page let's import the cancel game from the store slices and game init and also let's import use dispatch from react redux let's initialize the dispatch as a call to use patch and now in this on click handler we are going to call dispatch and we are going to dispatch the cancel game action now let's refresh and type our name and of course this moves too quickly so the fetching my internet connection is pretty good and i get the questions really quick but we can do something so that we can see this this cancel button longer and we can actually test if it works so let's go into saga we're gonna import the delay effect from redux saga effects and here before we call our api we're gonna yield a delay of a thousand milliseconds so one second now if i refresh type a name and i have time to click the cancel button and it doesn't work because i you have to call the dispatch function like this not just pass the reference to it okay let's try that again so refresh name start game press the cancel and we start the game which will start the fetching we cancel the game which puts our state to the start game but our fetch questions still goes on so it's not being cancelled that's an issue because now we are in the game state we have questions but our user didn't want to finish playing let's fix that so in saga here where we fork this fetch question saga we can actually store that in a constant so let's call it forked saga and now we are going to yield another fork and this time to cancel the fetch quiz i'm gonna call it cancel fetch quiz and i'm gonna pass the forked saga to it and inside of this cancel fetch quiz it's gonna be another generator function and here we are going to handle the cancellation of our fetch of our fetch questions saga inside of this cancel fetch quiz generator function we are going to create an infinite loop and inside of this we are going to yield take and here we are going to wait for the cancel game action so let's import that real quick from the game init cancel game and we are going to wait for cancelgame.type and if we receive that action we are going to yield cancel so this cancel is another effect from redux saga with which we can cancel forked effects so we're gonna cancel and here we receive the forked saga and we can cancel it this way when we dispatch the cancel game action we will cancel the fetching of the question so that won't happen anymore let me refresh i'm gonna type my name press start and then press cancel and now you can see we don't actually get the dispatched fetch questions success anymore going further we will have to handle our game page so now if we type our name press start game we get to this game game page and here we are going to play our game for the game logic we are going to create a new saga called game.js inside of this inside of this we are going to export default a function called gig a generator function actually called game saga and here we will have our main logic for the game for this let's create our import from redux saga effects we're going to get the take from now redux saga effects and in an infinite loop we are going to yield take and here we will wait for the fetch questions success so our game starts when we get the dispatch for fetch questions success from the slices and it was in the game slice okay so when fetch questions success dot type so when this action is is dispatched we will write our logic for the game for the logic we will have 60 seconds time and if the user doesn't answer all the questions either way the game will be finished and will give him the results for the number of questions that he answered to have a 60 second timer we are going to get another effect called race this allows us to create a race so only the first finisher effect will be terminated the other ones will be cancelled and we'll erase two different effects one of them are called delay and i'll just set a delay of 60 seconds so 60 000 milliseconds i also my id auto imported it here and the other effect is going to be called done and here this done effect will be another saga i'm gonna call it answers saga for the moment it's not created so let's create it real quick so it doesn't draw never so function gamesup game saga and this is it after either of these finishes so either 60 seconds passes or in this game saga it will finish when we answer all the 10 questions after this we will dispatch an action called finish game so let's create that real quick and after that we'll go and create our game saga in the game in its slice we will have another reducer called finish game state action and this will just set the state dot stage to be equal to stages dot end game now let's go back into our game saga import this finish game from slices game init and also let's get the put effect and after this race we are going to yield put and put the finish game now let's add this game saga to our good saga so here we're going to import game from saga and game and let's add it to the yield all so game and we're gonna run it now we seem to have an error so what did i do wrong i have the default export and i mistakenly named this again game saga so it's supposed to be answers saga now if i refresh okay another ever we did not export the finish game from the init so if we go into gaming it slice we have to also export this finished game action okay now it's it's supposed to work so let's test it i'm gonna first set this delay to a shorter period so let's set it to two seconds because i don't want to wait 60 seconds type the name press start game okay this didn't work because the delay of two seconds actually takes two seconds to finish but this is an empty saga so nothing happens inside it so let's create our core logic for it here we are going to have a 4 here we are going to have a 4 let i equals 0 i less than 10 i plus plus and inside of this i we are going to yield take and this take will have to get the answer question action that action will be dispatched when the user clicks on the answer for a question so we won't be able to test this now i'll just set it back to 60 seconds so i don't forget and we'll test it a little bit later after we create that action here in this take we will have to wait for an action called answer questions so we will create that and when that action is dispatched we will put another action called next question so this way the we will handle the logic in the reducers for when the user answers a question we will check if it's correct and we'll also dispatch another action to load the next question let's do that real quick so inside of our game slice we will create those two actions so let's create the answer question one first it's gonna get the state and the action and inside of this we will have to do some logic so let's first find out what is the current question so current question is going to be state dot questions and here for this we are going to get the state dot current question index now let's update the score if the user added a correct answer so state dot score is going plus equals and now we will have to do our ternary if check so action dot payload dot answer so we will have to get an answer inside the payload we will check if that is equal to current question dot correct underscore answer and if that is true then we will add one to our score else we will add zero and this is it for now so we just update the score if that is correct and let's also create the next question reducer which also gets the state and the action and inside of this we are just going to set the state dot current question index to plus equal one so this way we get the answer question action and here we handle the logic for updating the score in the next question action that is dispatch we handle updating the current question index now let's export these actions before i forget again so answer question and next question and let's go into our game saga import answer question and next question from the slices and the game and now we will wait for the answer question action and we will dispatch yield what the next question this should be it for the answers saga so now the rest will be inside of our ui but now we can test this so we can test if this race actually works let me refresh the page set this delay to two seconds now refresh again and now i type my name press the start game fetch question success and after two seconds you can see our game state finish game action was dispatched and our screen moved to the end screen now it works okay let's set this delay back to 60 seconds and let's move to our game page and create the ui for it so in the game page here let's first import the use selector and use dispatch hooks from react redux i'm gonna already initialize the use dispatch hook because we'll need it later and now let's display our first question inside of our ui we'll create a constant called current question this is gonna be a call to use selector we're gonna get the state and return state dot quiz dot questions and from the questions array so from this array right here we will get the state dot quiz dot current question index with two hours okay so now whenever this current question index changes our question will be changed now let's display that question so i'm gonna create a p tag here and our question is gonna be inside of this but it's in the in html form so so we have to set the dangerously set inner html of this p tag to be equal to an object with underscore underscore html and to that we pass the current question now if i refresh let me refresh the page and press start game okay it's an object because here from this we get the object and i should get the we get so in this state we get an object and i should get the question key from that object and now you can see it refreshed and we get our first question now let's also get the score and the current question index so let's create a new constant call score it's going to be again a use selector we get the state and return state dot quiz dot score and also the state dot current question index and use selector state and we return state dot quiz dot current question index and we can display these at the top so let's create another p tag score and put the score here and also create another p tag with the let's put it like current question index then a slash and out of 10. now let's refresh see how that looks okay so we have the score and the question that we are right now okay next let's create the buttons for answering true and false here we will have a button which is gonna say do and i'm gonna copy it just one time and the other one is gonna say false and the on click handler for this is gonna be a call to a function which is gonna be called answer question not the one that we have in the other part of our application and to this we are going to pass a string with two with the upper with an uppercase t and we're gonna do the same for the false but we're gonna pass an uppercase false now let's handle this let's create this answer question function it's gonna get the answer and inside of it we will have to dispatch the answer question action let's dispatch actually let's rename this function to answer handler because our answer question is the action so let's name it like this and we're gonna dispatch this answer question action from the slice answer question with the answer that the user clicked on so the this sensor needs to be to go and false with uppercase letters so we can compare them to the ones that we receive from the api okay let's see how that looks now bad logic in the checking okay so this doesn't seem to work because my score doesn't update at all so let's go back to our game slice and check if this answer questions reducer works here actually this reducer looks good i believe the problem is that i didn't send this the answer as an object but i actually sent it here as just the answer so i'm gonna put it inside of an object and let's try that again so name start game and now if we answer correctly you can see i answered six quit i'm at the sixth question but my score is four when we finish all the questions we are moved to the end stage even if the 60 seconds didn't pass okay let's also add a button also here so it's gonna be another button this time we're gonna dispel dispatch of finnish game action which will end our game doesn't matter if we used up all our questions so on click we're gonna have a end game handler actually let's just pass a reference to it because we don't need any parameters and the button will say quit game now let's create that const and game handler inside of this endgame handler we are going to dispatch and we have to get the finished game action from our slice so let's import finish game from the store slices slices and game in it and now we can dispatch the finish game so this should be pretty quick let's type our name the game answer a few questions and then press the quit game and it takes us to the end screen directly and i wrote quiz not quit okay now the last thing the game page needs right now is a timer so we don't at the moment display how much time the user has left let's do that so for that we need we're gonna need use state and use effect from react we are going to create a new state so const time left and set time left is going to be a call to use state and we're going to initialize it with 60 seconds and then we are going to create a use effect and inside of this this use effect will only be run once so that's why we put this empty array and inside of this empty array we're gonna create an constant con called interval and we're gonna set an interval here and in this interval we're gonna set the time left we're gonna get its previous value and return previous minus one and this interval will be run at every a thousand milliseconds just so we do some cleanup at the end we're gonna return from this use statehook we're gonna return a function and we're gonna clear the interval and pass the interval constant okay let's display it here so time left and we put the time left constant now let's refresh the page name loading and now our time left is being displayed right here okay i can also quit game and it takes me to the end screen okay our game is almost finished we have we still have this end game page and we also have that those answers that we didn't store until now so we can display the questions that were answered with the true and false correct answers so first let's create the endgame page on this end game page we will just need a button so on this for the moment we'll just have a button that is gonna say restart game and we're gonna have an on click handler with the restart handler function let's create that restart handler okay and from this we will dispatch an action so let's get use dispatch from react redux it's not causing its import okay let's initialize it const dispatch equals use dispatch and let's call it empty for now here because we haven't created that restart game action so let's go into the game in its slice here after finish game let's create a restart game action it gets the state and the action and this is gonna be a pretty simple reducer it's just gonna do the same thing as the cancel game so we're gonna set the stage to start game if you want you can also set the score to zero right now but i am setting the score to zero here in slice gs when the questions are fetched successfully so it doesn't really matter you can do it any way you like now in the game minute slice let's export this restart game action in the end page i'm gonna import restart game from store slices and game init and here we are going to call this and dispatch this restart game okay now if i press restart game oh i have to refresh first again finish the game quit game and if i press restart it takes me to the first screen so this works next let's handle the storing of the answered questions so we can display them on the end screen for that let's go into the game slice and here when we answer a question we will push them inside of an array so let's add the answers array initialized as an empty array and in the initial state when we have to also set this this array to empty when we fetch the questions successfully so we don't store on top of other questions so it's going to be an empty array and now when we answer a question we have to store that answer question inside of this array so we will do state dot answers dot push and inside of this this we will push an object which will contain the question which will be the current question dot question this way we will have the text for that question the answer is gonna be action dot payload dot answer next the correct answer is gonna be the current question dot correct underscore answer and we can have an is correct state right here so we have a boolean and we can change the color of the text based based on this boolean so we'll have one is correct which is gonna be action dot payload dot answer being equal to current question dot correct answer okay this is it now if i refresh type the name now when i answer a question you can see on the answer questions dispatch we can see in the answers array we have the state for our answered question so this is all that we need for this question now let's go into the end game page and on this endgame page let's display these questions that we answered so for that we're gonna need the use selector hook here we are going to create a new constant called answers which is going to be a call to use selector will get the state and return state state dot quiz dot answers okay now let's display this question so we're gonna just do a simple map here we're gonna do answers dot map we're gonna get an answer and now for this we're gonna create a p tag and we're gonna put answer dot question and then we can also do answer dot answer which is gonna be true or false and if you want to we can do answer dot correct underscore answer so we have both of them don't worry this will be styled nicer later but for now we can just do this so let's refresh the page try something answer a few questions and here you can see we have we don't have the correct answer because after the second line we don't have anything so let's see why so inside of the answer is array oh it's correct answer with an uppercase a so correct answer now if i refresh you can see both both of them here don't worry we'll style these later but for now everything works we can also display the score right here real quick so let's create a new constant called score and use selector state and return state dot quiz dot score and we're gonna put it right here so your score was score out of 10. okay now you may notice these strange characters here because by mistake i didn't put the answer in dangerously set in html so let's do that real quick i'm going to create a div here instead of the p tag i'm going to put a paragraph and here dangerously set inner html is going to be an object underscore underscore html is gonna be answer dot question and i'm gonna remove it from here okay now it looks better we have all those commas and everything that was using html entities now the only part left is to add the styling for the styling we are going to use tailwind css i don't want to use normal css for this because tailwind is more fun and you can also add styling quicker with it if you just learn the basics so let's first add tailwind to our app i'm just gonna search so go to telugu in css docs slash installation i'm going to leave the link in the description below and here we're going to choose create react app and it tells us what we have to do so i already have the project then we have to install tailwind via npm so i'm gonna copy this close my development server and run the npm command while we wait for the npm install to finish i want to show you real quick about uh intellisense extension for vs code that will help you add class names easier to your project so you just have to search for tailwind and it's the first one here it's called tailwind css intellisense make sure you have this installed and as you see here in this example if you start typing class names it will give you really great suggestions so that way you won't have to remember all the class names okay now that this uh was installed we next have to install also crackle because this is how we'll run our projects right okay now that cracker was installed we will have to change something in our package.json so let me close all of these open package.json and we will replace the first three scripts with the ones from the documentation okay save this next we are going to create a cracker.config file and put this this configuration from the documentation so new file crack dot and paste this next we will have to initialize our tailwind css configuration file so we'll run mpx tailwind css in it and it will generate a tailwind.config.js for us and it will generate a tailwind.config.js for us inside of this it's the default configuration you can extend your teams and add custom variables to it and a lot of configuration in tailwind i won't go into the details because this is not a tailwind crash course or something if you want me to make one of those let me know in the comments below the last step we have to do to configure tailwind is just replace this purge line what we get from the docks so it removes on unused styling in production so this way only the styling that is actually used in the project will remain in the production bundle okay and the last thing is to include the tailwinds in our css file so in index.css so that's why i left this index.css empty i'm going to paste these and the last step in the documentation is to import the index.css but that is already imported in this project okay now we can run mpm start and if you look in the console this will run crack or start not re not the default react one and after development server starts we will continue with our styling for the application great now our development server is running and we can continue adding tailwind to our app i'm going to close these two tabs and also close all the files so as you can see tailwind stripped some of our styling so it resets some of the default styling for the elements like for this button or for the input we will have to add those styles by ourselves let's get started so first let's go to the main page and here we have the just the displayed page but i want to add some styling to it so i'll create a div instead of the react fragment on this div we'll put up the class name attribute and here inside we add our tailwind classes so we style our application i'm gonna use for the whole application uh font mono so it's a mono space font we're gonna use background purple 50 okay and you can see for the under the button you can see we have a slight background color now let's also set the min height to screen this will set it to 100 viewport heights and now we have a light shade of purple here at the top i want to also have a header which is gonna have be like a title for our game so i'm gonna call it redux saga quiz game and on this let's do uh the class names background purple 500 text is gonna be white four pixels of padding also let's make the text big like 2x text to excel set it text center and also make it uppercase so this is the way you add styling to tailwind it's really neat and it cuts your development time by a lot okay so this is it for the header now we can go into the different pages and style them as we go along the first one is going to be the start game page so let's go here we have this div and let's add the class name and on this we are going to do display flex flex direction column justify center and also items center and also let's set the margin top of 80 and that will position all of them in the center i'm not going to create a separate component for the input because we just have this one so i just add class name to it and for this let's do a padding on the y axis of two p x four so on the horizontal axis remove the outline so outline none rounded that will give it a border radius shadow w64 so this will make it like around 300 pixels and the margin bottom six and you can see our input looks pretty nice now we can type into it you can also add some focus styling to it but i'm just gonna leave it like this i like the way it looks for the button we are going to create a separate component because we're going to use it in multiple places so i'm going to create a components folder inside of this i'm going to put a button.js and here let's create a button component real quick so i'm going to use rafc again from the es7 extension we are going to get some props here so i'm gonna destructure the children the on click handler the type and i'm gonna create a property called add class names so the type is gonna be either error or a normal button and add class names i'm gonna use this if you want to add different styling to our button for a specific button on top of the default styling so from this we are just going to return a button the button is gonna be the text inside of it is gonna be the children so we'll use it just like a normal button tab now let's put the on click handler as the on click and let's do the class names as a string template later this time not just a simple string because we'll attach some different variables to it first before we style it i'm going to import it into the start game page so we see what we are doing to it so import button from out components button and replace our button okay i'm not going to put any type on this one because this one is going to be a normal button and i also don't want any additional styling on this one but we'll have it ready now let's create the color based on the type so the default color is going to be i'm just going to call it purple and we'll create a class name based off of this color and now if type is error then we set the color to be red now let's create our styling so the background so the property name normally is boogu line color and the number 5100 and then it goes up up to 900 but this time we are going to use the color variable color and 500 so this is going to be the background color now if i save you can see we have the this nice purple color and if we put a property of type being error then this button will change to red okay next on hover we want to set the background and again the same color to two tones darker so now if i uh between hover and hover colon and the property you you can't have any spaces and now it's the light color and it changes color when we hover then on focus we want to not have any outline so outline none a padding vertical 3 px 6 then text is gonna be white we go we're going gonna put a shadow and make it rounded and at the end we're gonna add the add class names variable that we have so if we want to have any more styling to this we just put an add class names property on the button and that styling will be added at the end so if we want for example to replace the shadow we just have to write it again here okay so this is our ui for the start page now let's go further and style the fetching page so the this page that is displayed when the to be able to see the fetching page for long enough so we can style it let's go into the gameinit saga so here where we fetch the questions and set this delay to more so i'm going to set it to 60 000. setting this delay will allow us to see the loading screen for long enough so we can style it so if i type my name press start game now the loading screen they will take 60 600 000 milliseconds to go to the next steps and actually call the api this way we can style it so let's go to the fetching page now this p tag right here we're not gonna actually display that so i'm gonna delete that and replace it with a simple div and inside of this div i'm gonna put another one and from this we are going to make a nice spinner so on the first one let's add the class name and inside of this class name we're gonna make it with the width of 16 so w16 h also 16 so we have a square then we are going to make the background purple and 500 then we're gonna make it rounded dash full to make it a circle we're gonna display flags items center and a margin bottom of 12 so it pushes the bottom button a little bit down so let's save that and now we have a circle before we style the moving thing inside the circle let's place everything in the middle so on the topmost div let's add flex flex column justify center items center and a margin top of 80. and now everything is in the center let's go further with this div in the middle so on this one we're gonna add the class name we're going to put w12 h also 12 so another square this time we're going to make the background purple 200 around it full again so it's going to be a circle inside of a circle and it's gonna look like this it should be in the center but it's not it's just on the vertical axis in the center so i have to add just defy center to the darker purple div and now the circle is in the middle with this on this circle we want it to animate and tailwind has a few default animations one of them will work really nicely for this so i'm gonna add the next class animate bounce and if i save now you can see our circle bounces inside of the other one i pretty much like this for a spinner for this game it won't be displayed for too much anyways and for the button let's import our button component so import button from components button and replace the html button and this is it so this is all we have a spinner and the cancel button if i click the cancel button it takes us back to our initial screen now let's remove this delay that we added so this one right here you can remove the whole delay so not set it back to one second and now if i save refresh the page type the name press start game we see the loading for really quick and then the game loads now let's go further and style this game page so again we are going to need to set a delay because now we have 60 seconds until this screen disappears and that won't be long enough so let's go into the game saga so game.js and here in the race we will set the delay we will just add one more zero to it now our timer will be off so it will be able to go past zero because the race won't be finalized after 60 seconds and we can style everything in this okay let's go to the game page and here we will style every item so the first one is the container we're gonna set the class name display flex flex direction column items center and we're gonna position it relative because we will have this quit button positioned absolute okay now it disappeared i have to refresh the page because i didn't refresh it when i set the delay type the name press start and now everything is displayed flex so we want a circle here at the top in which we have the time the score will be on the left and the number of questions on the right let's do that for now so we just want the number of seconds so i'll remove this time left then let's add a class name and let's do it like this we will have an h20 so height 20 with also 20 flex justify center items center border of 8 pixels border purple 500 and rounded dash full and now if i save you can see we have this really nice circle that starts from the top of the screen now let's just move it a little bit down because it's merged with the header so an m y so margin on the a margin on the y axis of four the text let's make it three xl so let's make it bigger and also text purple 500 500 to to add that purple color and now we have this nice timer okay next let's do the score so i'll delete this text right here because i don't want it i just want the number and let's do class name and on this let's position it absolute top 4 left 4 and text will be 2 xl so a little bit smaller than the timer and also text purple 500 now if i save our score moves here to the right for the number of questions we will do kind of the same but on the right side of the page and this is it for the score and the question number now we have to go further and style the container for these for the question so for the question text and then we'll add the buttons so on the p tag let's add the class name and here we will do something really simple so padding 7 then a background white rounded and the shadow this is it we don't i don't want to add anything more you can read the question really nicely so for me it's enough if you want to style it more go ahead now for these two buttons i will actually add a div to be able to move them around easier and inside of this div i'm just gonna add the class name display flex justify this time it's gonna be justified between so justify space between width of 96 and margin top of eight and now we have two buttons next let's import the button component so import button from components button and replace these two buttons and that's it for these two buttons now we can press to go on false and the last one is this quit game so let's add another div so we can move it around i'm gonna put the button inside it and on this div we're gonna add a class name and position it abso absolute bottom four right four and replace this button and additionally i want it to be red so i'll set the type to be error and now you can see we have this button right here because i put the div on the it's relative to this container div right here which goes which has which has the height until here but i want it actually on the same level with that div so i'm gonna cut it put it on the same level and now let's wrap everything in a react fragment so it doesn't whenever and now our button is safe here at the bottom now if we click it it will move us to the end screen lastly we will have to style the end page so let's go there and here we will have to add all the elements so add all the question and here so i'm gonna press restart game type it then answer the questions because i want to have something to style and here we have the data for our end game page so let's start with the container so i'll do class name and on this we'll have flex flex column items center nothing too special now on the score let's do let's do a class name text to excel so pretty big and the margin bottom of four so it pushes this restart game button a little bit down also on top of it i want to add an h1 which is gonna say game over and let's also style this one so class name and for this let's do text three excel so a little bit bigger than the score text purple five five hundred and a margin on the y-axis of four pixel okay this looks pretty nice also let's put the score so this uh so the scope that the user got inside of a span and will make that also purple so let's do class name and text purple 500 and now we have the score the user got highlighted for the button we will just import the button component import button from components button and replace our html and we have a button okay and now we have to style these answers so i'll put them inside of a div so we can position them and add some margins if we need and i'll add a margin top of four and a padding all around of also four then we will have to move around the the things that we added until now so i'll change it up a little bit i'll delete this really quick we will have a div inside of this div we will have this p tag which has the question and then i don't want the correct answer and the and the user's answer i just want one of them so i'll keep the user's answer i'll delete this correct answer put the put the user's answer inside of a span and now we can style both of them so first on the div let's add the class name so it's gonna be a border bottom of two pixel board the purple 500 flex justify between and a background of white okay this looks pretty good now on the p tag let's add some padding to it so class name let's do padding of two pixels and a margin right of also two so it has some space between this and the answer okay and now let's style the span so class name on this class name we will do a template literal so let's add padding of two so it looks nice and centered like the other one and here we will change the color of the text based on if the user answered correctly or not so if answer dot correct answer is equal to answer dot answer then we will have text green 500 and if the answer was not correct we will have text read 500 500 okay now if i save you can see we have six correct answer questions and they are marked with green and the questions that were answered wrong are marked with red and you have the correct the user's answer right here so if they are marked with it the user knows this is not the answer this was it so now we have a fully styled game i can refresh the page type my name here and let's play it for once so true true false i'm just gonna type get them all random and i got a four out of ten the game works i can press the restart game and i'm taken back to the loading screen so this was it it was a pretty long video but i hope you learned a lot we went through a lot of different redux toolkit functions redux saga we also added tailwind css so a lot of new features and a lot of new functionality this was my favorite way to learn redux saga and also use redux toolkit in a different way i hope you really enjoyed it if you did let me know in the comments below don't forget to like the video and subscribe to the channel so i'm motivated to make more videos like this thank you all for watching and have a great day
Info
Channel: Raul Terhes
Views: 2,286
Rating: undefined out of 5
Keywords:
Id: C9g-Zhsd_FE
Channel Id: undefined
Length: 92min 48sec (5568 seconds)
Published: Fri Mar 05 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.