Build a Quiz App in React – Step by Step with Source Codes ( Part 2)

This is  Part two of out Quiz App Tutorial in React. Please see Part 1 if you have not.

In this part, we would put together the various functions, states and pieces that make up the quiz. So let’s get started!

The various part of of the code includes

 

The States

First, we would try to understand the states of the component. I have outlines the 6 different states i think we would need. So copy and paste the code. I will not speak on this as the comment are very clear

state = {
    userAnswer:null, //current users answer
    currentIndex:0,  //current questions index
    options: [],     //the four options
    quizEnd: false,  //determines if it's the last question
    score: 0,        //holds the score
    disabled: true   // determines the status of the buttons
}

 

The loadQuiz() Function

This function is responsible for loading  a single question based on the currentIndex state

So it first gets the current index which is an integer value. Then it reads the question on that index from the QuizData component. Finally, using the values it read, it updates the question, options and answer state and returns them. Of course, this changes in state is reflected in the UI as well.

//Component that holds the current quiz
loadQuiz = () => {
    const {currentIndex} = this.state //get the current question index
    this.setState(() => {
        return {
            question: QuizData[currentIndex].question,
            options : QuizData[currentIndex].options,
            answer: QuizData[currentIndex].answer          
        }
    }
    )
}

 

The nextQuestionHandler()

This function is executed when the user clicks on the “Next” button.

First, it obtains the user’s answer, the correct answer and the score. Then it increments the currentIndex. Finally, it checks if the userAnswer is equal to the correct answer and if so, increments the score. I hope this is clear as well.

So you can type it out yourself.

nextQuestionHander = () => {
    const {userAnswer, answer, score} = this.state
    this.setState({
        currentIndex: this.state.currentIndex + 1
    })
    //Check if correct answer and increment score
    if(userAnswer === answer){
        this.setState({
            score: score + 1
        })
    }
}

 

The checkAnswer() Function

This function executes when the user select an options. It simply sets the userAnswer state and then enables the next button (disabled = false)

//Check the answer
checkAnswer = answer => {
    this.setState({
        userAnswer: answer,
        disabled:false
    })
}

 

The finishHandler() Function

This function simply checks if the quiz has gotten to the last question. Then it sets the quizEnd state to true.

finishHandler =() => {
    if(this.state.currentIndex === QuizData.length -1){
        this.setState({
            quizEnd:true
        })
    }
}

 

componentDidMount() and componentDidUpdate()

The first one, componentDidMount() would simply call the loadQuiz() function to load the first question once the component mounts. In this case, the currentIndex has been initialized to 0.

componentDidUpdate() however would check if the state has changes, and if so, it loads the next question. As it loads a new question, it also sets the disabled state to true. This means that the next button would be disabled until the user selects an option.

 

The render() method

This is the most involving method. But I would try to explain it very clearly. I also recommend you follow with the video for a clearer understanding. This is the method that actually display the question to the output

The first thing it does is to get all the necessary states that it requires.

Next, it checks if the quiz has gotten to the last question. If so, it renders the results text, then tells the user his score and then displays the correct answers.

However, if the last question has not been reached, it displays the question at the current index together with the four options. Then it responds to the following events:

  • when an answer is selected: in this case, it executes the checkAnswer() function
  • when the Next button is clicked: call the nextQuestionHandler()

Also note the following:

  • the four options are displayed using the map method
  • conditional formatting applied to the answer buttons
  • the className of the Next button

Other aspects of the code is explained in the video

render() {
    const {
        question, options, currentIndex, userAnswer, quizEnd} = this.state //get the current state
    
    
    if(quizEnd) {
        return (
            <div>
                <h1>Game Over. Final score is {this.state.score} points</h1>
                <p>The correct Answers for the quiz are</p>
                <ul>
                    {QuizData.map((item, index) => (
                        <li className='ui floating message options'
                            key={index}>
                                {item.answer}
                        </li>
                    ))}
                </ul>
            </div>
        )
    }
            
    return (
        <div>
            <h2>{question}</h2>
            <span>{`Question ${currentIndex} of ${QuizData.length -1}`}</span>
            {options.map(option => (  //for each option, new paragraph
                <p key={option.id} 
                className={`ui floating message options
                ${userAnswer === option ? "selected" : null}
                `}
                onClick= {() => this.checkAnswer(option)}

                >
                    {option}
                </p>
            ))}
            {currentIndex < QuizData.length -1 &&
            <button 
            className="ui inverted button"
            disabled = {this.state.disabled}
            onClick = {this.nextQuestionHander}
                >Next Question</button>
            }
                {currentIndex === QuizData.length -1 &&
                <button
                className="ui inverted button"
                disabled = {this.state.disabled}
                onClick = {this.finishHandler}
                >Finish</button>
                }
        </div>
    )
}

So complete and test the application. As I mentioned, ensure to follow with the video. Also feel free to reach me if you have any challenges!
Congrats for getting this far!

User Avatar

kindsonthegenius

Kindson Munonye is currently completing his doctoral program in Software Engineering in Budapest University of Technology and Economics

View all posts by kindsonthegenius →

Leave a Reply

Your email address will not be published. Required fields are marked *