Reputation: 23
When mapping data from api to render component, i want to shuffle array once. But when i clicked any of answers button, answers array shuffle again. Here is code and https://codesandbox.io/s/wonderful-bartik-p4utm9?file=/public/index.html
// 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(()=> {
setRestart(false)
fetchData()
},[restart])
// 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}/>
)
})
Upvotes: 0
Views: 84
Reputation: 429
Simple solution: In the declaration of Data Const [Data,setData] = useStat([]] Then befor calling the fetch api check if not Data.length ===0 then proceed
Upvotes: 1
Reputation: 23
SOLVED! Moved shuffle function from mapping component part to the fetchData function.
const fetchData = async () => {
await fetch("https://opentdb.com/api.php?amount=5&type=multiple")
.then((response) => response.json())
.then((data) => {
for(let question of data.results) {
question.incorrect_answers = shuffle([...question.incorrect_answers, question.correct_answer])
}
setData(data.results)})
}
Upvotes: 0
Reputation: 26
The issue is caused by the "shuffle" function you're calling in your "questionElements" function.
The following is what is currently happening:
Each time your "Quiz" component renders, it invokes the "questionElements" function, which inside it calls the "shuffle" function.
In your "Question" component, when you select an answer, the onClick event invokes the "toggleBtnBgColor" function
In the "toggleBtnBgColor" you dispatch the "calculate" action which changes the "score" value in the Redux slice.
Your "Quiz" component is using the "score" value from store in the "useSelector" which means that whenever this value changes, the entire component will re-render.
When this component re-renders it will call "questionElements" which will then call "shuffle" yet again. Thus your issue.
What I would do to fix this issue, is on initial render, use useEffect to shuffle all question answers in the order you'd like and then store them in the components state and then map through those. Any further state updates won't re-shuffle them.
Upvotes: 0