Having a Radio Group reusable component which should be able to set a default option selected.
This is how the component is called:
const App = () => {
const drinks = [
{
label: "Coffee",
name: "drinks-list"
},
{
label: "Tea",
name: "drinks-list"
},
{
label: "Water",
name: "drinks-list",
disabled: true
}
];
const [selectedValue, setSelectedValue] = useState<String>(drinks[1].label);
function radioGroupHandler(event: React.ChangeEvent<HTMLInputElement>) {
setSelectedValue(event.target.value);
}
useEffect(() => {
console.log(selectedValue);
}, [selectedValue]);
return (
<PageLayout>
<RadioButtonGroup
label="Select your drink:"
options={drinks}
onChange={radioGroupHandler}
/>
</PageLayout>
);
};
export default App;
There is a line that sets the state:
const [selectedValue, setSelectedValue] = useState<String>(drinks[1].label);
The expected behaviour in this case would be to check the second option (Tea) when the component is rendered but it doesn't work like that - it renders the first option. I would expect to render the first option if the code would be like this:
const [selectedValue, setSelectedValue] = useState<String>(drinks[0].label);
This is RadioButtonGroup component:
const RadioButtonGroup = ({ label, options, onChange }: IInputGroup) => {
function renderOptions() {
return options.map(({ label, name, disabled }: IOption, index) => {
const shortenedOptionLabel = label.replace(/\s /g, "");
const optionId = `radio-option-${shortenedOptionLabel}`;
return (
<RadioButton
value={label}
label={label}
key={optionId}
id={optionId}
name={name}
disabled={disabled}
defaultChecked={index === 0}
onChange={onChange}
/>
);
});
}
return (
<Fieldset>
<Legend>{label}</Legend>
<Wrapper>{renderOptions()}</Wrapper>
</Fieldset>
);
};
export default RadioButtonGroup;
And here is RadioButton:
const RadioButton = ({ label, id, disabled, ...rest }: InputElementProps) => {
return (
<Wrapper>
<Radio id={id} type="radio" disabled={disabled} {...rest} />
<Label htmlFor={id} disabled={disabled}>
<span>{label}</span>
{/* disabled && <DisabledIcon small /> */}
</Label>
</Wrapper>
);
};
export default RadioButton;
Maybe it's easier on this code sandbox: https://codesandbox.io/s/custom-radio-button-group-forked-1do5u4?file=/src/App.tsx
Any idea what is wrong and why isn't the second option checked by default when the state is set useState<String>(drinks[1].label);
?
CodePudding user response:
It seems that the checked value is fixed with defaultChecked={index === 0}
, perhaps this could be replaced by checked={label === selectedValue}
to make this component fully controlled.
Forked live on: codesandbox
Example:
In RadioButtonGroup
, include selectedValue
as a prop so that the child component would know which option is selected:
<RadioButtonGroup
label="Select your drink:"
selectedValue={selectedValue}
options={drinks}
onChange={radioGroupHandler}
/>
In RadioButton
, use checked
instead of defaultChecked
for conditional check:
<RadioButton
value={label}
label={label}
key={optionId}
id={optionId}
name={name}
disabled={disabled}
//