简体   繁体   中英

Disable individual buttons in React based on Id?

I am trying to build a multiple choice quiz app using React. I am using state to increment the user's score when the correct answer button is clicked however I want the user to be able to 'click' the correct button once as a selection. I have found if the user clicks the correct answer button multiple times each click increases their score.

I have tried to apply a disable key to each of the buttons and use state to change the state to true once the button is clicked however unfortunately this affects every button.

Is there a way I can incorporate the ID in the question Array?

I want each individual answer button to be disabled once clicked.

My code so far:


  const questions = [
    {
      questionText: 'What is the Capital of France?',
      answerOptions: [
        { id: 0, answerText: 'London', isCorrect: false },
        { id: 1, answerText: 'Paris', isCorrect: true },
        { id: 2, answerText: 'Nice', isCorrect: false },
        { id: 3, answerText: 'Lyon', isCorrect: false },
      ],

    },
    {
       questionText: 'What is the Capital of the UK?',
       answerOptions: [
         { id: 0, answerText: 'London', isCorrect: true },
         { id: 1, answerText: 'New York', isCorrect: false },
         { id: 2, answerText: 'Sydney', isCorrect: false },
         { id: 3, answerText: 'Bath', isCorrect: false },
       ],

     },
     {
      questionText: 'Who turns out to be the true victor in the Battle of Armageddon in Mortal Kombat?',
      answerOptions: [
        { id: 0, answerText: 'Liu Kang', isCorrect: false },
        { id: 1, answerText: 'Shang Tsung', isCorrect: false },
        { id: 2, answerText: 'Raiden', isCorrect: false },
        { id: 3, answerText: 'Shao Kahn', isCorrect: true },
      ],

    },
    {
      questionText: 'Under what pseudonym did Stephen King publish five novels between 1977 and 1984?',
      answerOptions: [
        { id: 0, answerText: 'Richard Bachman', isCorrect: true },
        { id: 1, answerText: 'J. D. Robb', isCorrect: false },
        { id: 2, answerText: 'Mark Twain', isCorrect: false },
        { id: 3, answerText: 'Lewis Carroll', isCorrect: false },
      ],

    },
  ];


const [startQuiz, setStartQuiz] = useState(true);

    function startClick() {
    setStartQuiz(current => !current);
     }

const [score, setScore] = useState(0);

   const optionClicked = (isCorrect) => {
    if (isCorrect) {
      setScore(score + 1);
    }
  }



  const [disabled, setDisabled] = useState(false);

  const [showResults, setShowResults] = useState(true);

  function resultsClick() {
    setShowResults(current => !current);
   }


   function restartQuiz() {
    setStartQuiz(current => !current);
    setShowResults(current => true);
    setScore(0);
    setDisabled(false)
   }


    return(
      <div>
      {startQuiz ? 
        <div className="start-screen">
        <div className="start-text">
          <h1>Quizzical</h1>
            <p>Test your knowledge!</p>
            <button onClick={startClick}>Start Quiz</button>
         </div>
         
       </div> 
       
       : 


       <div className="quiz">
       
        
         <div className="firstQuestion">
            <h2>{questions[0].questionText}</h2>
            </div>
              <div className="firstAnswers">
              {questions[0].answerOptions.map((answerOption) => {
              return (
                <button key={answerOption.id}
                  
                  disabled={disabled}

                  onClick={() => { 
                  optionClicked(answerOption.isCorrect);
                  
                  setDisabled(true);
                  }}>
                  {answerOption.answerText}
                </button>
                    );
                  }
                )}
                    </div>


          <div className="secondQuestion">
            <h2>{questions[1].questionText}</h2>
            </div>
              <div className="secondAnswers">
                {questions[1].answerOptions.map((answerOption) => {
                return (
                <button key={answerOption.id} 
                  disabled={disabled}
                  onClick={() => {
                  optionClicked(answerOption.isCorrect)
                  setDisabled(true);
                  }}>
                  {answerOption.answerText}
                </button>
                    );
                  }
                )}
                    </div>

          <div className="thirdQuestion">
            <h2>{questions[2].questionText}</h2>
            </div>
              <div className="thirdAnswers">
                {questions[2].answerOptions.map((answerOption) => {
                return (
                <button key={answerOption.id}
                  disabled={disabled}
                  onClick={() => {
                  optionClicked(answerOption.isCorrect)
                  setDisabled(true)
                  }}>
                  {answerOption.answerText}
                </button>
                    );
                  }
                )}
                    </div>

         <div className="fourthQuestion">
            <h2>{questions[3].questionText}</h2>
            </div>
              <div className="fourthAnswers">
                {questions[3].answerOptions.map((answerOption) => {
                return (
                <button key={answerOption.id} 
                  disabled={disabled}
                  onClick={() => {
                  optionClicked(answerOption.isCorrect)
                  setDisabled(true)
                   }}>
                  {answerOption.answerText}
                </button>
                    );
                  }
                )}
                    </div>

        
<br></br>
        <div className="resultsSection">
           <button onClick={()=> resultsClick()}>
             Check Answers!
           </button>
           <h3 className="resultsText">{showResults ? <p>Score:</p> : <p>Score: {score}/4</p>}</h3>
           <button onClick={restartQuiz}>Restart Quiz</button>
       </div>


</div>

        
 }
</div>
 
    )
}```

First and foremost, it would be great if you could create a reusable component for each set of question+answers to avoid writing too much repeated code eg

function Question({questionText, answerOptions}) {
  return <>
    <div className="question">
      <h2>{questionText}</h2>
    </div>
    <div className="answers">
      {answerOptions.map((answerOption) => {
        return (
          <button key={answerOption.id}
            disabled={disabled}
            onClick={() => {
              optionClicked(answerOption.isCorrect)
              setDisabled(true)
            }}>
            {answerOption.answerText}
          </button>
        )
      }
      )}
    </div>
  </>
}

Next, you could use the useState hook to store an array of numbers indicating which answer option has been clicked:

const [disabledOptions, setDisabledOptions] = useState([])

Edit the optionClicked function such that it receives both the option id and the isCorrect boolean, and add the option id to the disabledOptions array

const optionClicked = (optionId, isCorrect) => {
   const newDisabledArray = [...disabledOptions, optionId];
   setDisabledOptions(newDisabledArray);
   if (isCorrect){
      setScore(score + 1);
   }
}

Final code will look something like this:

function Question({questionText, answerOptions}) {
  const [disabledOptions, setDisabledOptions] = useState([])
  const optionClicked = (optionId, isCorrect) => {
     const newDisabledArray = [...disabledOptions, optionId];
     setDisabledOptions(newDisabledArray);
     if (isCorrect){
        setScore(score + 1);
     }
  }

 
  return <>
    <div className="question">
      <h2>{questionText}</h2>
    </div>
    <div className="answers">
      {answerOptions.map((answerOption) => {
        const {id, isCorrect, answerText} = answerOption;
        return (
          <button key={id}
            disabled={disabledOptions.includes(id)}
            onClick={() => {
              optionClicked(id, isCorrect)
            }}>
            {answerText}
          </button>
        )
      }
      )}
    </div>
  </>
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM