I am having issues with (I think) the timing of the sequential calls to setState variables... specifically in my 'handleStartOverClick()' call. This function makes two 'setState' calls, builds a list, then selects a random item from that list. However, my console.logs in that method are showing that nothing is actually getting cleared, and the new list isn't getting built. I am pretty sure this isn't the best 'react way' to handle the synchronous nature of these calls, but I just haven't been able to find a way to properly handle from the docs/otherwise.
So far I've tried wrapping in useCallback(), making the methods async to use .then, and even brute forcing a timeout in between calls just to see it work. But no luck.
Also, I've included the json that is being pulled in with the import of 'questionsJson' at the top, even though that is maybe an extraneous detail.
import React, { useEffect, useMemo, useState } from 'react';
import { Grid } from '@material-ui/core';
import questionsJson from 'assets/data/questions.json';
import { Question } from 'domains/core/models';
export default function Questions(): ReactElement {
const [leftOptionSelected, setLeftOptionSelected] = useState(false);
const [rightOptionSelected, setRightOptionSelected] = useState(false);
const [mainQuestionList, setMainQuestionList] = useState<Question[]>([]);
const [currentQuestion, setCurrentQuestion] = useState<Question | undefined>(undefined);
const [questionsLoaded, setQuestionsLoaded] = useState(false);
const removeQuestionFromMainQuestionList = useMemo(() => (questionToRemove: Question) => {
const updatedQuestionList = mainQuestionList.filter(question => question?.id !== questionToRemove?.id);
setMainQuestionList(updatedQuestionList);
},[setMainQuestionList, mainQuestionList]);
const getRandomQuestion = useMemo(() => () => {
for (let index = 0; index < mainQuestionList.length; index++) {
const numberOfQuestions = mainQuestionList.length;
const randomArrayPosition = Math.floor(Math.random() * numberOfQuestions);
const randomQuestion = mainQuestionList[randomArrayPosition];
setCurrentQuestion({
id: randomQuestion.id,
option1: randomQuestion.option1,
option2: randomQuestion.option2
});
removeQuestionFromMainQuestionList(randomQuestion);
console.log("new main question list", mainQuestionList)
}
},[mainQuestionList, removeQuestionFromMainQuestionList]);
const buildQuestionList = () => {
const questionList: Question[] = [];
const questionInfo = questionsJson.questionInfo;
for (let index = 0; index < questionInfo.length; index++) {
const currentQuestionSet = questionInfo[index];
let questions = currentQuestionSet.questions;
const questionLimit = currentQuestionSet.questionLimit;
for (let index = 0; index < questionLimit; index++) {
const numberOfQuestions = questions.length;
const randomArrayPosition = Math.floor(Math.random() * numberOfQuestions);
const questionToAdd = questions[randomArrayPosition];
questionList.push(questionToAdd);
questions = questions.filter(question => question?.id !== questionToAdd?.id);
}
}
setMainQuestionList(questionList);
console.log("initial question list", questionList);
setQuestionsLoaded(true);
}
useEffect(() => {
buildQuestionList();
}, []);
useEffect(() => {
if (questionsLoaded){
getRandomQuestion();
}
}, [questionsLoaded]);
const handleStartOverClick = () => {
console.log("in handle start over")
setCurrentQuestion(undefined);
console.log("current question", currentQuestion);
setMainQuestionList([]);
console.log("mainQuestionList", mainQuestionList);
buildQuestionList();
console.log("mainQuestionList", mainQuestionList);
setTimeout( () => {
getRandomQuestion();
console.log("current question after clearout", currentQuestion);
}, 4000);
}
const handleOptionClick = (sideClicked: string) => {
if (sideClicked == "left"){
setLeftOptionSelected(true);
setTimeout( () => {
setLeftOptionSelected(false);
getRandomQuestion();
}, 2000);
} else {
setRightOptionSelected(true);
setTimeout( () => {
setRightOptionSelected(false)
getRandomQuestion();
}, 2000);
}
}
return (
<Grid container direction="row" spacing={6}>
<Grid style={{ backgroundColor: "yellow"}} item xs={6}>
<div onClick={() => handleOptionClick("left")} style={{ pointerEvents: rightOptionSelected ? 'none' : 'auto'}}>
<div>{currentQuestion?.option1}</div>
</div>
</Grid>
<Grid style={{ backgroundColor: "green"}} item xs={6}>
<div onClick={() => handleOptionClick("right")} style={{ pointerEvents: leftOptionSelected ? 'none' : 'auto'}}>
<span></span>
<div style={{ backgroundColor: "green"}}>{currentQuestion?.option2}</div>
</div>
</Grid>
<Grid item xs={2}>
<button onClick={() => handleStartOverClick()}>
START OVER
</button>
</Grid>
</Grid>
);
}
{
"questionInfo":[
{
"category":"fun",
"questionLimit":2,
"questions":[
{
"id":1,
"option1":"Apple pie",
"option2":"Cherry pie"
},
{
"id":2,
"option1":"Jack",
"option2":"Jill"
}
]
},
{
"category":"lifestyle",
"questionLimit":2,
"questions":[
{
"id":3,
"option1":"Workout",
"option2":"Watch tv"
},
{
"id":4,
"option1":"Day",
"option2":"Night"
},
{
"id":5,
"option1":"Watch",
"option2":"Read"
}
]
},
{
"category":"interest",
"questionLimit":2,
"questions":[
{
"id":6,
"option1":"Cars",
"option2":"Baseball"
},
{
"id":7,
"option1":"Money",
"option2":"Fame"
}
]
}
]
}