im trying to make a quizz project fetching api of quiz with answers and questions im so in the api there is array of wrong answers(3) and one correct answer i try to output them as buttons and i outtput the 3 wrong answers so i thought i would push the correct answer into the wrong answers array and then randomly sort them and output as answers but i get the errot that array of answers isnt iterable can anyone help me to solve this problem and tell me if im going in the right direction or not ?
import './App.css';
import axios from 'axios'
import {useState,useEffect} from 'react'
function App() {
const [quiz,setQuiz] = useState([])
const [answer,setAnswer] = useState([])
useEffect(()=>{
axios.get('https://opentdb.com/api.php?amount=10')
.then(res=>{
setQuiz(res.data.results[0])
setAnswer([...quiz.incorrect_answers, quiz.correct_answer])
})
.catch(err=>{
console.log(err);
})
},[])
return (
<div className="App">
<h1>{quiz.question}</h1>
{answer && answer?.map(answers =>
<button key={answers}>{answers}</button>)
}
</div>
);
}
export default App;
CodePudding user response:
useEffect(()=>{
axios.get('https://opentdb.com/api.php?amount=10')
.then(res=>{
setQuiz(res.data.results[0])
let tempVar = res.data.results[0] ;
setAnswer([...tempVar.incorrect_answers, tempVar.correct_answer])
})
.catch(err=>{
console.log(err);
})
},[])
Your useEffect should look like this. As changing a state is an asynchronous task . That is why you are getting error that quiz.incorrect_answers is not iterable. I hope this solves your issue .
CodePudding user response:
You can't set state and use it immediately, you need to await the set state changes. You can handle that properly by adding a useEffect to be executed every time quiz changes you code will look like that
useEffect(() => {
axios
.get("https://opentdb.com/api.php?amount=10")
.then((res) => {
setQuiz(res.data.results[0]);
})
.catch((err) => {
console.log(err);
});
}, []);
useEffect(() => {
if (quiz.length > 0)
setAnswer([...quiz.incorrect_answers, quiz.correct_answer]);
}, [quiz]);
OR You can use .then function to handle that in the same useEffect
useEffect(() => {
axios
.get("https://opentdb.com/api.php?amount=10")
.then((res) => {
setQuiz(res.data.results[0]);
}).then(()=>setAnswer([...quiz.incorrect_answers, quiz.correct_answer]))
.catch((err) => {
console.log(err);
});
}, []);
CodePudding user response:
Here's an approach you can use:
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
// This here is a function to shuffle the array for you
const [quiz,setQuiz] = useState(null)
// use a null value for the quiz, null checking will be done in the h1 render component
const [correct_answer,setAnswerCorrect] = useState([])
// from the result, the correct answer is a string
const [incorrect_answers,setAnswersIncorrect] = useState([])
// and the incorrect answers are in form of an array
// that's why the separation
let all_answers = [];
useEffect(()=>{
axios.get('https://opentdb.com/api.php?amount=10')
.then(res=>{
setQuiz(res.data.results[0])
setAnswerCorrect([res.data.results[0].correct_answer])
setAnswersIncorrect(res.data.results[0].incorrect_answers);
// first update all the values
})
.catch(err=>{
console.log(err);
})
},[])
Then from here check whether the question has loaded first, if not, show that the question is loading:
<h1>{quiz ? quiz.question : 'Question loading...'}</h1>
// check whether the question has loaded before outputting it
{
all_answers = correct_answer && incorrect_answers ? shuffleArray(correct_answer.concat(incorrect_answers)) : ''
// join the two arrays, for the correct and incorrect answers then shuffle the values
}
{
all_answers?.map(answers =>
<button key={answers}>{answers}</button>)
}