Home > Mobile >  React onChange works only once
React onChange works only once

Time:12-05

I'm trying to recreate the functionality of ToggleButtonGroup and ToggleButton from react-bootstrap.

Here's my component:

import { useState } from 'react';
import ButtonRadio from "PointAndClick/components/ButtonRadio";
import { useSelector } from 'react-redux';
import { RootState } from '../../features/store';
import '../css/GameAnswers.css';
import GameImage from '../components/GameImage';

type GameAnswersProps = {
    setFinishedGame: Function
}

function GameAnswers(props: GameAnswersProps) {
    const gameAnswers = useSelector((state: RootState) => state.GameDataReducer.gameAnswers);    
    const gameImages = useSelector((state: RootState) => state.GameDataReducer.gameImages);
    const correctAnswer = useSelector((state: RootState) => state.GameDataReducer.correctAnswers);
    const gameQuestion = useSelector((state: RootState) => state.GameDataReducer.gameQuestion);
    
    const [selectedAnswer, setSelectedAnswer] = useState("");
    let iconAnswer = "";

    const handleAnswerChange = function (e: React.ChangeEvent<HTMLInputElement>) {
        console.log(e.target);
        setSelectedAnswer(e.target.value);
    }

    const determineButtonVariant = function (answer: string) {
        if (answer !== selectedAnswer) {
            return "primary";
        } else if (answer === correctAnswer) {
            props.setFinishedGame(true);
            iconAnswer="check";
            return "success";
        } else {
            props.setFinishedGame(false);
            iconAnswer="times";
            return "danger";
        }
    }

    return (
        <div className="game-answers">
            {
            gameImages === undefined &&
                    <GameImage 
                    className="game-details-image" 
                    images={[{ imgSrc: gameQuestion, imgAlt: 'test' }]} />
            }
            <div className="btn-group btn-group-custom">
                {gameAnswers.map(function (answer, index) {
                    return <ButtonRadio
                            id={answer}
                            value={answer}
                            onChange={handleAnswerChange}
                            className={`btn btn-${determineButtonVariant(answer)}${gameImages !== undefined ? "btn-img" : ""}`}
                        >
                        {gameImages !== undefined && 
                        <GameImage 
                        className="game-answers-image"
                        images={[{ imgSrc: gameImages[index], imgAlt: 'test' }]} />
                    }
                            {iconAnswer !== "" && determineButtonVariant(answer) !== "primary" ? 
                            <i className={`fa fa-${iconAnswer} fa-${iconAnswer}-custom`}/> :
                            ""
                            }
                            {answer}
                        </ButtonRadio>
                })}
            </div>
        </div>
    );
}

export default GameAnswers;

ButtonRadio.tsx

import "../css/Button.css";

type ButtonRadioProps = {
    className: string,
    children: React.ReactNode,
    name: string,
    id?: string,
    value?: string,
    onChange?: any
}

function ButtonRadio(props: ButtonRadioProps)
{
    return (
        <>
        <input
        type="radio" 
        id={props.id}
        value={props.value}
        className="btn-check"
        onChange={props.onChange}
        autoComplete="off"
        />
        <label 
        className={props.className}
        htmlFor={props.id}
        role="button"
        tabIndex={0}
        >
        {props.children}
        </label>
        </>
    );
}

export default ButtonRadio;

When I was using react-bootstrap, the only difference was the return function which looked like this:

return (
        <div className="game-answers">
            {
                gameImages === undefined &&
                    <GameImage 
                    className="game-details-image" 
                    images={[{ imgSrc: gameQuestion, imgAlt: 'test' }]} />
            }
            <ToggleButtonGroup type="radio" name="answers" className="btn-group-custom">
                {gameAnswers.map(function (answer, index) {
                    return <ToggleButton
                            id={answer}
                            value={answer}
                            onChange={handleAnswerChange}
                            variant={determineButtonVariant(answer)}
                            bsPrefix={gameImages !== undefined ? "btn-img" : ""}
                        >
                        {gameImages !== undefined && 
                        <GameImage 
                        className="game-answers-image"
                        images={[{ imgSrc: gameImages[index], imgAlt: 'test' }]} />
                    }
                            {iconAnswer !== "" && determineButtonVariant(answer) !== "primary" ? 
                            <i className={`fa fa-${iconAnswer} fa-${iconAnswer}-custom`}/> :
                            ""
                            }
                            {answer}
                        </ToggleButton>
                })}
            </ToggleButtonGroup>
        </div>
    );

and everything worked fine.

Now I tried to do it myself (the first piece of code in the post) and it works but only partially.

The onChange event is only called once on each button.

Example:

I click on answer1: onChange called
I click on answer2: onChange called
I click on answer1 again: onChange isn't called anymore (I expected it to be called again)

Why can this be happening and how can I fix it? I found already something on Google, but not useful to my case.

CodePudding user response:

So i think your main issue is due to you using onChange instead of onClick.

Had a bit of a rework here if this is any use to show you what i changed https://stackblitz.com/edit/react-ts-queeta?file=Hello.tsx

  • Related