Given the following unordered HTML/JSX list:
<ul className="settings">
<li>
<input type="radio" name="settings" id="beginner" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="beginner">Beginner</label>
</li>
<li>
<input type="radio" name="settings" id="intermediate" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="intermediate">Intermediate</label>
</li>
<li>
<input type="radio" name="settings" id="expert" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="expert">Expert</label>
</li>
<li>
<input type="radio" name="settings" id="custom" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="custom">Custom</label>
</li>
</ul>
with a submit button that fires the following function:
const onSubmit = (e: MouseEvent): void => {
console.log(selectedSetting.current)
}
I want to validate that at least one of these radio buttons have been selected. As you can see I was using a single useRef variable here which would cause the "custom" radio button to be logged every time. The straight forward solution, then, is to have a useRef for each radio button but is there an easier way to do this? Can I instead give the ul tag a ref and do something similar to jQuery to see if one of them has been selected?
You can handle the onClick event for the radio buttons in order to set state to the currently selected radio.
Something like this:
const { useRef, useState } = React;
const { render } = ReactDOM;
function App() {
const [selected, setSelected] = useState();
const selectedSetting = useRef();
const handleSettingsChange = e => setSelected(e.target.id);
const handleSubmit = () => {
selected
? alert("Selected radio: " + selected)
: alert("Nothing Selected!");
}
return(
<div>
<ul className="settings">
<li>
<input type="radio" name="settings" id="beginner" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="beginner">Beginner</label>
</li>
<li>
<input type="radio" name="settings" id="intermediate" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="intermediate">Intermediate</label>
</li>
<li>
<input type="radio" name="settings" id="expert" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="expert">Expert</label>
</li>
<li>
<input type="radio" name="settings" id="custom" ref={selectedSetting} onClick={handleSettingsChange}/>
<label htmlFor="custom">Custom</label>
</li>
</ul>
<div>
<button onClick={handleSubmit}>Submit</button>
</div>
</div>
);
}
render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
UPDATED ANSWER:
This would be a much cleaner, more "React" way to accomplish this...
const { useState } = React;
const { render } = ReactDOM;
const MY_RADIOS = ["Beginner", "Intermediate", "Expert", "Custom"];
function App({radios}) {
const [selected, setSelected] = useState();
const handleClick = radio => event => setSelected(radio);
const handleSubmit = () => {
let msg = selected
? "Selected radio: " + selected
: "Nothing Selected!";
alert(msg);
}
return(
<div>
<ul className="settings">
{radios && radios.map(r => {
return (
<li>
<label>
<input onClick={handleClick(r)} type="radio" name="settings" />
{r}
</label>
</li>
)
})}
</ul>
<div>
<button onClick={handleSubmit}>Submit</button>
</div>
</div>
);
}
render(<App radios={MY_RADIOS} />, document.body);
li {
list-style-type: none;
}
ul {
padding-left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With