Game of Thrones Quiz Game with React and GraphQL

Create The Questions component

Let’s create the Questions component, open the src/components/questions/index.js file and update the file with the following:

// src/components/questions/index.js

import React, { useState } from "react";
import gql from "graphql-tag";
import { graphql } from "react-apollo";

const Questions = ({ questions }) => { 
  return questions.length ? (
    <div>
      {showFinished ? (
        <div className="results">
          <img
            src="https://memegenerator.net/img/instances/70669406/your-watch-has-ended.jpg"
            alt="Your watch has ended"
          />
          <h3>
            Your results are out. You scored {score} out of {questions.length}
          </h3>
        </div>
      ) : (
       // TODO -- create component to render question here
      )}
    </div>
  ) : (
    <p>Loading</p>
  );
};

This is the base view of the component. It’ll get access to the data returned from the query and display a single question per time. Let’s update the component to add some more functionality to it.

//src/components/questions/index.js

import React, { useState } from "react";
import gql from "graphql-tag";
import { graphql } from "react-apollo";

const Questions = ({ questions }) => {
  const [currentIndex, setCurrentIndex] = useState(0);
  const [score, setScore] = useState(0);
  const [showFinished, setShowFinished] = useState(false);
  const currentQuestion = questions[currentIndex];

  const onNextClicked = selectedOption => {
    /_ here we check if the answer matches the selected option. If true,
    we increment the score for the user _/
    if (currentQuestion.answer === selectedOption) setScore(score + 1);
    /_ we check if the next index doesn't exist within the array. 
      This means we've exhausted all the questions, so __`showFinished`__ is set 
      to true _/
    if (currentIndex + 1 > questions.length - 1) {
      setShowFinished(true);
      return;
    }
    setCurrentIndex(currentIndex + 1);
  };

  const resetQuiz = () => {
    setCurrentIndex(0);
    setShowFinished(false);
    setScore(0);
  };

  return // TODO -- add return JSX value 
};

We’ll be making use of hooks to handle state within the component. A Hook is a special function that gives you access to React features. The useState is a Hook that lets you add React state to function components, it takes an initial value as an argument and returns an array containing the initial state and a function for updating the value.

After creating the state values, we get the initial question and display it as the currentQuestion. We also set up an event listener onNextClicked to navigate the user to the next question.

Within the onNextClicked callback, we check if the option selected by the user matches the answer to the question. If there’s a match, we increment the score value. We also when the user has exhausted all questions then we set the showFinished value to true. At the end of the function, we increment the currentIndex value which handles the currentQuestion value.

When the resetQuiz function is called, all the values are reset to their initial values.

Finally, replace the comment TODO -- add return JSX value with the snippet below:

return questions.length ? (
    <div>
      {showFinished ? (
        <div className="results">
          <img
            src="https://memegenerator.net/img/instances/70669406/your-watch-has-ended.jpg"
            alt="Your watch has ended"
          />
          <h3>
            Your results are out. You scored {score} out of {questions.length}
          </h3>
        </div>
      ) : (
        // TODO -- create component to render question here
      )}
      {showFinished ? (
        <button className="try-again" onClick={resetQuiz}>
          Try again
        </button>
        ) : (
        <div className="questions-progress">
          {currentIndex + 1}/{questions.length}
        </div>
      )}
    </div>
  ) : (
    <p>Loading</p>
  );

Let’s add some styles to the component. Create a file questions.css within the src/components/questions directory. Open it and copy the styles below into it:

.questions-progress {
  width: 60px;
  height: 60px;
  display: flex;
  margin: 0 auto 15px;
  align-items: center;
  justify-content: center;
  box-shadow: 0 5px 8px 1px rgba(0, 0, 0, 0.1);
  border-radius: 50%;
  color: rgba(0, 0, 0, 0.7);
  background: white;
  font-size: 16px;
  font-weight: bold;
  border: 4px solid rgba(0, 0, 0, 0.3);
  position: fixed;
  left: 50%;
  bottom: 5px;
}
.results {
  padding: 10px;
}
.results img {
  width: 100%;
  height: 300px;
  border-radius: 10px;
  object-fit: contain;
}

.results h3 {
  font-weight: bold;
  font-size: 23px;
  text-align: center;
}

.try-again {
  display: flex;
  align-items: center;
  border-radius: 8px;
  text-transform: uppercase;
  text-align: center;
  box-shadow: 0 5px 13px 1px rgba(0, 0, 0, 0.1);
  padding: 15px 30px;
  margin: auto;
  font-size: 17px;
  font-weight: bold;
  color: rgba(0, 0, 0, 0.8);
  border: 0;
  background: white;
  cursor: pointer;
}

Import the stylesheet into the questions component like so:

//src/components/questions/index.js

import React, { useState } from "react";
import gql from "graphql-tag";
import { graphql } from "react-apollo";
import Question from "../question";

import "./questions.css";

// rest of the file

Like this article? Follow @codebeast on Twitter