I am having trouble passing data from component to main file in react. It is a basic quiz application, get quiz objects from api and pass data to the "Question" component. In the main file i have score state to decide how many answers are correct. But when answer button clicked application see value in the component. I want to match answer value and correct answer and increase score by state. Here is the Question component and main file.
export default function Question(props) {
const [flag,setFlag] = React.useState(true)
// TOGGLE BUTTON BACKGROUND COLOR WHEN BTN CLICKED
function toggleBtnBgColor(btn) {
if(flag) {
btn.target.classList.toggle("dark-bg-color")
setFlag(false)
}
}
return (
<>
<div className="question" key={props.index}>{props.question}</div>
{props.answers.map((answer,index)=> {
return (
<button key={index} onClick={toggleBtnBgColor} className="answer-button">{answer}</button>
)
})}
<hr></hr>
</>
)
}
Main file;
const [data, setData] = React.useState([])
const [score, setScore] = React.useState(0)
const [startAgain, setStartAgain] = React.useState(false)
// FETCH QUIZ DATA FROM API
const fetchData = async () => {
await fetch("https://opentdb.com/api.php?amount=5&type=multiple")
.then((response) => response.json())
.then((data) => setData(data.results))
}
React.useEffect(()=> {
fetchData()
},[])
// SHUFFLE ALGORITHM TO USE LATER
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
// RENDER QUESTIONS
const questionElements = data.map((question, index) => {
// ANSWERS ARRAY AND SHUFFLE
let answers = [...question.incorrect_answers,question.correct_answer]
shuffle(answers)
return (
<Question key={index} index={index} question={question.question} answers={answers}/>
)
})
// CALCULATE FINAL SCORE WHEN CHECK BTN CLICKED
function calcScore() {
for(let question of questionElements) {
console.log(question.calcScore)
}
setStartAgain(true)
}
return (
<div className="question-container">
{questionElements}
<p>{startAgain && ("Your score is " score "/5")}</p>
<button onClick={calcScore} className="check-button">{!startAgain ? "Check Answers" : "Restart Quiz"}</button>
</div>
)
CodePudding user response:
Check this out, we pass a function to Question that receives the answer and index. The parent will update an array that carries all the answers
https://codesandbox.io/s/black-cdn-p6lo5v?file=/src/App.js
const setAnswer = (index, answer) => {
const newAnswers = [...answers];
newAnswers[index] = answer;
setAnswers(newAnswers);
};
// RENDER QUESTIONS
const questionElements = data.map((question, index) => {
// ANSWERS ARRAY AND SHUFFLE
let answers = [...question.incorrect_answers, question.correct_answer];
shuffle(answers);
return (
<Question
key={index}
index={index}
question={question.question}
answers={answers}
setAnswer={setAnswer}
/>
);
});
CodePudding user response:
If I am not wrong I understand that you want to update parent component's state. You can pass setState function as props to child component like this:
return (
<Question key={index} index={index}
question={question.question}
answers={answers}
updateScore ={setScore}/>
)
CodePudding user response:
- You can make use of props for the same and pass setScore hook to set the values.
- You can make use of Redux and get/set the values to/from it.
Most people prefer redux over passing the setState hooks to children as props, however many times people pass the hook as props and solve this.
Hope this helps you!