Home > database >  Radio input won't check when used to set state
Radio input won't check when used to set state

Time:12-01

I'm new to React and am trying to create this trivia app from an API.

I'm currently trying to store the answers selected by the user so that I can then compare them with the correct answers.

I'm using radio inputs for the possible choices for the answers, and my idea is to update my state once the radio input is checked. I am able to update the state (at least it looks like it on the console), but the button won't check and in this case, I can't style it.

For context: I'm pulling 5 multiple choice questions from the API and I have 3 components: <App />, <Quiz />, and <Question />.

Here's the <App /> content:

import { useState, useEffect } from 'react'
import './App.css'
import Quiz from "./components/Quiz"

function App() {
    const [quiz, setQuiz] = useState(false)
    const [data, setData] = useState([])
    const [score, setScore] = useState(0)
    const [countCorrect, setCountCorrect] = useState(0)

    function startQuiz() {
    setQuiz(true)
    }

    useEffect(() => { // fetch data from API and save it on the data state
    fetch("https://opentdb.com/api.php?amount=5&difficulty=easy&type=multiple")
        .then(response => response.json())
        .then(data => setData(Object.values(data)[1]))
    }, [])  

    return (
    <main className="container">
        {!quiz ? 
        (<section className="starter--container">
        <h1>Quizzical</h1>
        <button onClick={startQuiz}>Start quiz</button>
        </section>) :
        <Quiz data={data}/>
        }
    </main>
    )
}

export default App

And here's the <Question />, which is where the problem is

import { useState } from "react";
import { nanoid } from "nanoid";

export default function Question({ data }) {
    const [userSelections, setUserSelections] = useState([{
        question1: "",
        question2: "",
        question3: "",
        question4: "",
        question5: "",
    }]);
    
    function handleQuestion(event) {
        const { name, value } = event.target

        setUserSelections(prevState => {
            return {
                ...prevState,
                [name]: value,
            }
        })
    }
    
    return (
        <div className="quiz--container">
        {data.map(({ question }, index) => {
            data[index].id = index;
            const currentIndex = data[index].id;

            const currentAnswers = data.find((question) => question.id === currentIndex);
            const allChoices = [...currentAnswers.incorrect_answers, currentAnswers.correct_answer].sort(() => Math.random() - 0, 5);
            
            return (
            <div key={index} className="question--container">
                <p className="question">
                    {question.replace(/&quot;/g, '"').replace(/&#039;/g, "'")}
                </p>
                <form className="choices--container" key={nanoid()}>
                    {allChoices.map((choice, index) => {
                        const questionNumber = `question${currentIndex   1}`
                        const optionNumber = `Option${index   1}`
                        
                        return (
                            <div className="choice" key={index}>
                                <input 
                                    type="radio" 
                                    id={`${questionNumber}${optionNumber}`}
                                    name={questionNumber}
                                    value={choice}
                                    onChange={handleQuestion}
                                />
                                <label className={`choice--label`} htmlFor={`${questionNumber}${optionNumber}`}>
                                    {choice}
                                </label>
                            </div>
                        )
                    })}
                </form>
            </div>
            );
        })}
        </div>
    );
}


I tried to include checked={userSelections.questionNumber === choice} to the input element, but then I noticed the state is updating in a weird way: it's creating a new nested object instead of updating the original, like in the screenshot below:

enter image description here

CodePudding user response:

Just add checked props and check conditionally selected answer.

<input
  type="radio"
  id={`${questionNumber}${optionNumber}`}
  name={questionNumber}
  value={choice}
  selected={true}
  onChange={handleQuestion}
  checked={choice === userSelections[questionNumber]}
/>;
  • Related