Game of Thrones Quiz Game with React and GraphQL: Create The Questions component
Publikováno: 17.6.2019
Let’s create the Questions component, open the src/components/questions/index.js
file and update the file with the following:
// src/componen...
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