I'm fetching async object with an array and a value. I want to take the array and add that other value to the same array at a random index.
{
incorrect_answers: ['item1', 'item2', 'item3'],
correct_answer: 'item4'
}
// I expect this: ['item1', 'item2', 'item4', 'item3'] the index for 'item4' is random
I get the array with useState fine, but don't know how to add the other value in the same useState line:
const [index, setIndex] = useState(0);
const [answers, setAnswers] = useState([]);
useEffect(()=>{
(async () => {
const data = await fetch ('https://opentdb.com/api.php?amount=10&type=multiple');
const json = await data.json();
setAnswers(json.results[index].incorrect_answers);
//if I use .splice here, I get only the correct_answer in the array
answers.splice(random,0, json.results[index].correct_answer);
setAnswers(answers)
})();
}, []);
UPDATE:
the complete project is here: https://codepen.io/metsuge/pen/qBxyrMY The idea is that when clicking Next Question, the index would update to show the next object in the array. But the index value in NextQuestion() and in the if statement is off by 1, so questions and answers are mixed
CodePudding user response:
- Your 2nd
setAnswer
may point to the oldanswers
array as callingsetAnswer
can async.
const [index, setIndex] = useState(0);
const [answers, setAnswers] = useState([]);
useEffect(()=>{
(async () => {
const data = await fetch ('');
const json = await data.json();
setAnswers(json.results[index].incorrect_answers);
// answers may equal to []
answers.splice(random,0, json.results[index].correct_answer);
setAnswers(answers)
})();
}, []);
- React will batch your two
setAnswers
calls and will only call the 2ndsetAnswer
. So yourincorrect_answers
will never set to theanswers
array. Therefore you are actually splicing the initial empty array.
- You are mutating the original data. so somehow if you manage to set the
incorrect_answers
before insert thecorrect_answer
and still usesanswers.splice
, then the original data will be mutate. So after you mutate the original data set, you call thesetAnswers(answers)
with mutated data. When react compares the old value to the new value provided insetAnswers
it sees both are equal. So React will ignore state update.
How you can fix the issue
const [index, setIndex] = useState(0);
const [answers, setAnswers] = useState([]);
useEffect(()=>{
(async () => {
const data = await fetch ('');
const json = await data.json();
const data = json.results[index].incorrect_answers;
data.splice(random,0, json.results[index].correct_answer);
setAnswers(data);
})();
}, []);
References
- https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
- https://reactjs.org/docs/react-component.html#state
UPDATE
I have update your QuizeComponent
function QuizComponent() {
const [APIData, setAPI] = useState({});
const [question, setQuestion] = useState("");
const [index, setIndex] = useState(0);
const [answers, setAnswers] = useState([]);
const [objectsLength, setObjectsLength] = useState(0);
useEffect(() => {
(async () => {
const data = await fetch(
"https://opentdb.com/api.php?amount=10&type=multiple"
);
const json = await data.json();
setAPI(json.results);
setObjectsLength(json.results.length);
})();
}, [])
useEffect(() => {
if (APIData[index]) {
const random = Math.floor(Math.random() * 5);
const data = APIData[index];
const cpy = [...data.incorrect_answers];
cpy.splice(random, 0, APIData[index].correct_answer);
setAnswers(cpy);
setQuestion(data.question);
}
}, [index, APIData])
const nextQuestion = function () {
if (index !== objectsLength.length - 1) {
setIndex(index 1);
setQuestion(APIData[index].question);
setAnswers(APIData[index].incorrect_answers);
} else {
console.log("This is the last question.");
}
};
return (
<div className="QuizComponent">
<h1>QUIZ COMPONENT</h1>
<div>
<Question question={question} APIData={APIData} index={index} />
</div>
<div>
<button onClick={() => nextQuestion(index)}>Next question</button>
</div>
<div id="main-answers-container">
{answers.map(function (item, i) {
return <Answer key={i} answer={item} index={index} />;
})}
</div>
</div>
);
}
CodePudding user response:
In my console your code is working fine. I am thinking that the problem must be that you are doing operations on your state variable. You can try to do a deep copy of the array, then use splice, and then setState. Something like this:
const deepCopy = [...answers]
deepCopy.splice(random,0, json.results[index].correct_answer);
setAnswers(deepCopy)