Home > Software engineering >  Radio button keeps re-rendering when clicked
Radio button keeps re-rendering when clicked

Time:12-06

I'm fetching data from an API, and I map over it in order to generate 5 groups of radio buttons. Everything works fine, except for the fact that when I click on any of the input radio buttons, it seems to re-render the entire component or something, as you can see below (this is only one of the groups, but it happens and affects all of them):

enter image description here

Here's the code:

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

export default function Question({ data }) {
    const [userSelections, setUserSelections] = useState({
        question0: "",
        question1: "",
        question2: "",
        question3: "",
        question4: "",
    })

    function handleSelection(event) {
        const {name, value} = event.target

        setUserSelections(prevSelection => {
            return {
                ...prevSelection,
                [name]: value
            }
        })
    }

    const renderQuestionBlocks = data.map(({question, correct_answer, incorrect_answers, uniqueQuestionId}, questionIndex) => {
        const allAnswers = [...incorrect_answers, correct_answer].sort((a, b) => 0.5 - Math.random())
        data.uniqueQuestionId = nanoid()

        return (
            <form className={`question--container question${questionIndex}`} key={data.uniqueQuestionId}>
                <p>{question.replace(/&quot;/g, '"').replace(/&#039;/g, "'")}</p>
                
                {allAnswers.map((answer, answerIndex) => {
                    data[questionIndex].uniqueAnswerId = nanoid()
                    
                    return (
                    <div 
                        key={data[questionIndex].uniqueAnswerId}
                        className={`choice--container question${questionIndex}`}
                    >
                        <input 
                            type="radio"
                            name={`question${questionIndex}`}
                            id={`question${questionIndex}option${answerIndex}`}
                            value={answer}
                            checked={userSelections[`question${questionIndex}`] === answer}
                            onChange={handleSelection}
                        />
                        <label htmlFor={`question${questionIndex}option${answerIndex}`}>{answer.replace(/&quot;/g, '"').replace(/&#039;/g, "'")}</label>
                    </div>
                    )
                })}             
            </form>
        )
    })
    
    return (
        <div className="questions--container">
            {renderQuestionBlocks}
            <button>Check answers</button>
        </div>
    )
}

CodePudding user response:

it seems to re-render the entire component or something

Updating state re-renders a component. This is expected and correct (and fundamentally necessary) behavior in React. But... What does your component do when it renders?

It randomly sorts the values:

const allAnswers = [...incorrect_answers, correct_answer].sort((a, b) => 0.5 - Math.random())

It sounds like either that sort shouldn't be random, or should be randomized outside the scope of this component, or that randomization should itself be persisted in state so you can re-use it on each render.

For example, if you just need a random number for the component then you can generate one and keep it in state:

const [randonNumber] = useState(Math.random());

This will randomly generate a number, but won't re-generate one on every render. Then you can consistently use the same randomly generated number:

const allAnswers = [...incorrect_answers, correct_answer].sort((a, b) => 0.5 - randonNumber)
    
  • Related