Home > Enterprise >  React - how to access other elements in handleClick?
React - how to access other elements in handleClick?

Time:09-27

I am iterating over an array, and for each element, I pass it to a handleClick function. The question is, inside that handleClick function, how do I access the rest of the elements?

const listOfAnswers = questions[questionNumber].possibleAnswers.map((obj, i, arr) => {
        return (
            <Button
                key={i}
                style={
                    {
                        margin: '15px 0',
                    }
                }
                variant='contained'
                onClick={e => handleClick(obj, e, arr)}
            >
                {obj.answer}
            </Button>
        )
    })
const handleClick = async (obj, e, arr) => {
        const { isCorrect, answer } = obj

        if (isCorrect) {
            setScore(score   1)
            e.target.style.backgroundColor = 'green'
            await delay(100)
            e.target.style.backgroundColor = ''
        } else {
            e.target.style.backgroundColor = 'red'

            await delay(100)
            e.target.style.backgroundColor = ''
        }

        nextQuestion()

    }

What I am trying to do is: when a user clicks on the right answer, that button turns green. This is straightforward to implement. When a user clicks the wrong answer, it turns red. Also simple to implement. But what I want is: when a user clicks on the wrong answer, I want the right answer to turn green. For this I think I need to be able to access the rest of the elements, because in the handleClick function, you only have access to a single, individual element.

CodePudding user response:

const [clicked, setClicked] = useState(-1);

const listOfAnswers = questions[questionNumber].possibleAnswers.map((obj, i, arr) => {
    return (
        <Button
            key={i}
            style={
                {
                    margin: '15px 0',
                    color: clicked == -1
                      ? "#ffffff"
                      : clicked == i && obj.isCorrect
                      ? "#00ff00"
                      : cliked != i
                      ? "#ffffff"
                      : "#ff0000"
                }
            }
            variant='contained'
            onClick={e => handleClick(i)}
        >
            {obj.answer}
        </Button>
    )
})
const handleClick = async (i) => {
   setClicked(i)
   nextQuestion()
}

CodePudding user response:

There are various way to do it:

  1. Add a answer to the state (initialized to undefined). Your handleClick will set this state to the answer the user selected. Then if answer is defined, pass a green backgroundColor in the style of the correct button (next to your margin). And on the button whose obj.answer === answer, if obj.isCorrect is false, set a red backgroundColor. (note you would need to reset answer state to undefined in your nextQuestion)
  2. Add a ref to the correct answer Button (https://reactjs.org/docs/refs-and-the-dom.html), and on handleClick, you can set ref.current.style.background.
UPDATE with example of ref

The following assumes that there is a unique correct answer:

const correctAnswerRef = useRef(null);
const listOfAnswers = questions[questionNumber].possibleAnswers.map((obj, i, arr) => {
        return (
            <Button
                key={i}
                ref={obj.isCorrect ? correctAnswerRef : undefined}
                style={
                    {
                        margin: '15px 0',
                    }
                }
                variant='contained'
                onClick={e => handleClick(obj, e, arr)}
            >
                {obj.answer}
            </Button>
        )
    })

const handleClick = async (obj, e, arr) => {
        const { isCorrect, answer } = obj
        // always set current answer to green
        correctAnswerRef.current?.style.backgroundColor = 'green'
        if (isCorrect) {
            setScore(score   1)
        } else {
            e.target.style.backgroundColor = 'red'
        }
        await delay(100)
        e.target.style.backgroundColor = '';
        correctAnswerRef.current?.style.backgroundColor;

        nextQuestion()

    }
  • Related