Steytz
Steytz

Reputation: 394

React hooks state undefined on handle function

I am creating a simple quiz with persisting response state and i am currently stuck trying to figure out why responseState is undefined in my handleAnswerClick function, this function is triggered much later if at all per click. By then the States should all be set.

const Question: React.FC<IProps> = (props) => {
const [responseState, setResponseState] = useState([]);
const [question, setQuestion] = useState<IStateProps>(props.id);
const [answers, setAnswers] = useState([]);
const [choice, setChoice] = useState();

const initialResponseState = () => {
    const data = {
        duration: '00:01:00',
        examTakerProgress: 1,
        question: props.id,
        answer: '1',
    }
    axios.post(`${host}/api/responseState/`, data)
        .then(() => {
            console.log('Created the initial Response State');
        })
        .catch((err) => {
            console.log(err);
        })
}

const getData = async () => {
    await axios.all([
        axios.get(`${host}/api/question/${question}`),
        axios.get(`${host}/api/responseState/examTakerProgress/1/question/${props.id}`)
    ])
        .then(axios.spread((questionData, responseData) => {
            if (!responseData.data.length > 0) {
                initialResponseState();
            }
            setResponseState(responseData.data);
            setQuestion(questionData.data);
            setAnswers(questionData.data.answers);
            setChoice(responseData.data.length > 0 ? responseData.data[0].answer : '');
            setTimeout(() => {
                props.toggleLoading();
            }, 50);

        }))
        .catch(err => console.error(err));
};

useEffect(() => {
    getData()
}, [])


const handleAnswerClick = async (number: number) => {
    setChoice(number);
    const data = {
        duration: '00:01:00',
        examTakerProgress: 1,
        question: props.id,
        answer: number,
    }
    await axios.put(`${host}/api/responseState/${responseState[0].id}/`, data)
        .then((data) => {
            console.log(data);
            console.log('choice changed to :' + number);
        })
        .catch((err) => {
            console.log(err);
        })
}

if (props.loading) {
    return <Loader/>
}

return (
    <React.Fragment>
        <h3>{question.label}</h3>
        <p className='mb-3'>{question.description}</p>
        <ListGroup as="ul">
            {answers.map((answer, index) => {
                    if (answer.id === choice) {
                        return <ListGroup.Item key={answer.id} action active> <Answer key={index}
                                                                                      answer={answer}/></ListGroup.Item>

                    } else {
                        return <ListGroup.Item key={answer.id} action onClick={() => {
                            handleAnswerClick(answer.id)
                        }}><Answer key={index}
                                   answer={answer}/></ListGroup.Item>
                    }
                }
            )}
        </ListGroup>
    </React.Fragment>
)};

Can someone explain me the reason why this is happening?

Upvotes: 2

Views: 3286

Answers (3)

Steytz
Steytz

Reputation: 394

Basically i am creating a responseState when a question loads for the first time, if a question is afterwards reloaded the State is already there since it is persisted. This means i also have to make sure to call setResponseState for the first case where the ResponseState still does not exist.

const initialResponseState = () => {
const data = {
    duration: '00:01:00',
    examTakerProgress: 1,
    question: props.id,
    answer: '1',
}
axios.post(`${host}/api/responseState/`, data)
    .then(() => {
            setResponseState(res.data)
        console.log('Created the initial Response State');
    })
    .catch((err) => {
        console.log(err);
    })}

Upvotes: 0

Vencovsky
Vencovsky

Reputation: 31565

Reasons why responseState is undefined.

  1. The most obvious is that you set responseState to undefined

The only place you call setResponseState is in getData where you have setResponseState(responseData.data);, so please check if responseData.data isn't undefined.

  1. You never get to call setResponseState and the initial state is an object but you try to get responseState[0].id

I'm not sure what data type you are handling, but if you defined const [responseState, setResponseState] = useState({}); with the default value of useState as {} and then try to access responseState[0].id, there is two things happening.

Either you have an object with number keys or you have an array, but if you have an array, you should declare the initial value as an array.

But this isn't the problem, the problem is that you might never get to the part where you call setResponseState(responseData.data); and then you will have responseState to be {} and when trying to do responseState[0] it will be undefined, and when calling responseState[0].id you will get an error saying that you cannot read id of undefined.

Ways to fix this

  1. Debug your code, make sure that the api call returns what you are expecting and setResponseState(responseData.data); is called.

  2. Check if responseState[0] exists before try to access responseState[0].id

I would be able to help more, but you didn't add more information, so it's hard to help, but above is what I think it's the problem

Upvotes: 1

Ramesh Reddy
Ramesh Reddy

Reputation: 10652

Based on this line

const [responseState, setResponseState] = useState({});,

the responseState is an object.

but in the handleAnswerClick function you are using it as an array ${responseState[0].id}.

Note that this actually works if the object has a 0 key but since you're getting undefined that is not the case.

Upvotes: 1

Related Questions