I created a question and answer app using react. Four questions are created in four components and each question has three options. The options are show in div. In first question we click an answer(out of any 3 options). Then click next button and show second question (second component). Then select an answer (out of any 3 options) for the second question. And so on till forth question and answer. After clicking previous and next button show the previous/next question and selected answer (state should be persisted for selected answer in all four questions when clicking next and previous button).
Here my main component:
import React from "react";
import Qustionone from "./qustionone";
import Qustiontwo from "./qustiontwo";
import Qustionthree from "./qustionthree";
import Qustionfour from "./qustionfour";
function Questions() {
return (
<div>
<h1>Question and Answer Program</h1>
<Qustionone />
<Qustiontwo />
<Qustionthree />
<Qustionfour />
<button>previous</button> <button>next</button>
</div>
);
}
export default Questions;
Qustionone.js
import React from "react";
function Qustionone() {
return (
<div>
<p>Qustion 1 ?</p>
<div>Answer1</div>
<div>Answer2</div>
<div>Answer3</div>
</div>
);
}
export default Qustionone;
Qustiontwo.js
import React from "react";
function Qustiontwo() {
return (
<div>
<p>Qustion 2 ?</p>
<div>Answer11</div>
<div>Answer22</div>
<div>Answer33</div>
</div>
);
}
export default Qustiontwo;
Qustionthree.js
import React from "react";
function Qustionthree() {
return (
<div>
<p>Qustion 3 ?</p>
<div>Answer111</div>
<div>Answer222</div>
<div>Answer333</div>
</div>
);
}
export default Qustionthree;
etc...
Here selected class is used to selected div and how write the react proper functionality for these working. I am new to react please help me, thanks in advance
CodePudding user response:
Look at the examples on the Internet something like this: How to Build a Quiz App Using React
CodePudding user response:
I'll try to split my answer into multiple sections, as it would be easier for me to answer the question, and for you to implement. These sections are the following:
- Handle questions navigation
- Handle answer selection
- Rendering question
I will also add a summary at the end with the complete implementation and some ideas for the future refactoring
Handle questions navigation
To implement the navigation among questions we will do the following things:
- Create the state
selectedQuestionIndex
- Create the handler for the navigation buttons clicks
- Assign the handler to each of the buttons
// ./questions.jsx
import React, { useState } from 'react';
const MIN_ACTIVE_QUESTION_INDEX = 0;
const MAX_ACTIVE_QUESTION_INDEX = 3;
const DIRECTION_PREV = -1;
const DIRECTION_NEXT = 1;
const limitWithinBoundaries = (val, min, max) => Math.max(min, Math.min(val, max))
function Questions() {
const [selectedQuestionIndex, setSelectedQuestionIndex] = useState(MIN_ACTIVE_QUESTION_INDEX);
const onNavigationButtonClick = (direction) => {
setSelectedQuestionIndex((currentSelectedQuestionIndex) =>
limitWithinBoundaries(
currentSelectedQuestionIndex direction,
MIN_ACTIVE_QUESTION_INDEX,
MAX_ACTIVE_QUESTION_INDEX
)
);
}
return (
// ...
<button onClick={() => onNavigationButtonClick(DIRECTION_PREV)}>previous</button>
<button onClick={() => onNavigationButtonClick(DIRECTION_NEXT)}>next</button>
);
}
Now by clicking on the buttons the selectedQuestionIndex
state will be changed within the range - [0, 3] and the component will be rendered on each state change
Handle answer selection
To implement this functionality we just need to create a state for all of the answers and handle the answer selection.
// ...
const replaceAnswerImmutable = (index, answer, answers) => {
const result = [...answers];
result[index] = answer;
return result;
};
function Questions() {
const [selectedQuestionIndex, setSelectedQuestionIndex] = useState(MIN_ACTIVE_QUESTION_INDEX);
const [answers, setAnswers] = useState([]);
// ...
const onAnswerClick = (event) => {
// we expect that the answer will be specified as a HTML data-answer atribute
const answer = event.target.dataset.answer;
if (!answer) return;
setAnswers((currentAnswers) =>
replaceAnswerImmutable(
selectedQuestionIndex,
answer,
currentAnswers
)
);
};
// ...
}
Not the answer will be recorded for the selected question each time onAnswerClick
is executed. onAnswerClick
will be used in the section below...
Rendering question
As the markup is similar for each question, we can implement a single component for that.
// question.jsx
import React from 'react';
function Question(props) {
const { data, onAnswerClick } = props;
const { question, answers } = data;
return (
<div onClick={onAnswerClick}>
<p>{question}</p>
{answers.map((answer) => (
<div key={answer} data-answer={answer}>{answer}</div>
))}
</div>
);
}
The content of the question and the related answers should be extracted as a dataset.
// ./dataset.js
const QUESTIONS = [
{ question: 'Qustion 1 ?', answers: ['Answer 1', 'Answer 2', 'Answer 3'] },
{ question: 'Qustion 2 ?', answers: ['Answer 1', 'Answer 2', 'Answer 3'] },
// ...
];
export default QUESTIONS;
Now we just need to render the Question
component with the selected question data and the onAnswerClick
handler
import React, { useState } from 'react';
import QUESTIONS from './dataset';
// ...
function Questions() {
const [selectedQuestionIndex, setSelectedQuestionIndex] = useState(MIN_ACTIVE_QUESTION_INDEX);
const onAnswerClick = (event) => {
// ...
};
const selectedQuestion = QUESTIONS[selectedQuestionIndex];
return (
<div>
<Question data={selectedQuestion} onAnswerClick={onAnswerClick} />
{/* buttons here */}
</div>
);
}
Summary
You can find the complete implementation and the working example at this sandbox.
Despite the component works, there is still room for refactoring. As you might notice, the Questions
component has a lot of code and I would suggest decomposing it into smaller chunks to improve readability and logic encapsulation. Something like this
import React from 'react';
import Question, { useQuestion } from './question';
import Navigation, { useNavigation } from './navigation';
function Questions() {
const { selectedQuestionIndex, onNavigationButtonClick } = useNavigation();
const { onAnswerClick, selectedQuestion } = useQuestion(selectedQuestionIndex);
return (
<div>
<Question data={selectedQuestion} onAnswerClick={onAnswerClick} />
<Navigation onClick={onNavigationButtonClick} />
</div>
);
}