Así que creé un componente de radio y ejecuté una función onChange, pero no se activa cuando otra radio con el mismo nombre de grupo anula la selección de la radio, ¿por qué?
Heres mi código para el componente de radio
import { useState } from 'react'; const RadioButton = (props) => { const [checked, setChecked] = useState((props.checked !== undefined) ? props.checked : false); const handleChange = () => { console.log('changed to: ' + checked); (checked) ? props.onChecked() : props.onUnchecked(); setChecked(!checked); } return ( <input type="radio" className={'border-grey custom-checkbox ' + (checked ? 'checked' : 'unchecked')} name={props.groupName} onChange={handleChange}/> ) } export default RadioButton;Se discute un problema similar en el controlador de eventos OnChange para el botón de opción (INPUT type="radio") no funciona como un valor
Una solución a esto es manejar los cambios y los estados de los botones de opción en el elemento padre.
Un ejemplo de cómo se hace esto:
const Parent = () => { const [buttons, setButtons] = useState([0, 0, 0]); const handleClick = (index) => { setButtons((buttons) => { alert(`prev radio ${buttons}`); // You add a condition of deselecting here if you want // if(buttons[index] === 1 ) return [0,0,0] const newButtons = [0, 0, 0]; newButtons[index] = 1; alert(`new radio ${newButtons}`); return newButtons; }); }; return ( <form> {buttons.map((_, index) => ( <RadioButton handleClick={handleClick} key={index} index={index} checked={buttons[index]} /> ))} </form> ); }; const RadioButton = ({ index, checked, handleClick }) => { return ( <input value={"" + index} type="radio" onChange={() => handleClick(index)} checked={checked} /> ); };Si necesita algunas etiquetas u otra cosa al lado del botón de opción, puede envolverlas juntas (reemplace el componente RadioButton con el componente a continuación)
const CustomInputWithOtherInfo = ({ index, checked, handleClick }) => { const otherInfo = [ { label:"label1", title:"title1" }, { label:"label2", title:"title2" }, { label:"label3", title:"title3" }, ] return ( <div> <h4>{otherInfo[index].title}</h4> <label>{otherInfo[index].label}</label> <input value={"" + index} type="radio" onChange={() => handleClick(index)} checked={checked} /> </div> ); };aquí puede encontrar una demostración en sandbox
https://codesandbox.io/s/react-playground-forked-ik1lo0?file=/index.js:129-335
Esto es una matanza excesiva. Pero ya que preguntaste, aquí tienes:
import React, { useEffect, useState } from "react"; import "./styles.css"; const arrRadios = [ { id: "1", text: "Text1", checked: false }, { id: "2", text: "Text2", checked: false }, { id: "3", text: "Text3", checked: false } ]; export default function App() { return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> <RadioGroup arrRadios={arrRadios} groupId="myGroup" /> </div> ); } function RadioGroup(props) { const [arrRadios, setArrRadios] = useState(props.arrRadios); const handleChange = (e) => { console.log(e.target.value); arrRadios.forEach((a) => { if (a.id === e.target.value) { a.checked = true; } else { a.checked = false; dispatchEvent(new Event(`rb-deselect-${props.groupId}-${a.id}`)); } }); setArrRadios([...arrRadios]); }; return ( <div> {arrRadios && arrRadios.map((radio) => ( <RadioButton key={radio.id} groupId={props.groupId} id={radio.id} text={radio.text} checked={radio.checked} handleChange={handleChange} /> ))} </div> ); } function RadioButton(props) { const onDeselect = () => { console.log(`I am deselected ${props.groupId} : ${props.id}`); }; useEffect(() => { window.addEventListener( `rb-deselect-${props.groupId}-${props.id}`, onDeselect, false ); return () => window.removeEventListener( `rb-deselect-${props.groupId}-${props.id}`, onDeselect, false ); }, []); return ( <> <input type="radio" name={props.groupId} value={props.id} onChange={props.handleChange} checked={props.checked} /> <span>{props.text}</span> </> ); }La idea es conectar un evento de deselección personalizado en el botón de radio que se activa (para todos) cuando se selecciona/cambia cualquier otra radio.