I'm working on a Radio Group and trying to make the radio's button checked value update upon a state update made by clicking another button. In the example below, I can only get the desired effect with the "key" prop. Is there any way to get this API working without the "key" prop:
https://stackblitz.com/edit/react-ts-vfehex?file=index.tsx
Steps to reproduce: [1] click buttons below RadioField and observe that the Radio doesn't update according to the value [2] Uncomment in the App the "key" prop on the RadioField [3] click buttons below the radiofield and observe the radiofield now updates
thank you!
CodePudding user response:
Try like this:
First, add a props inside every RadioFieldItem
to pass the selected
value:
<RadioField
// LOOK HERE
// key={selected}
selectedValue={selected}
>
<RadioFieldItem
selected={selected}
value="yes"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setSelected(e.target.value)
}
/>
<RadioFieldItem
selected={selected}
value="no"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setSelected(e.target.value)
}
/>
<RadioFieldItem
selected={selected}
value="maybe"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setSelected(e.target.value)
}
/>
</RadioField>
Then, inside the RadioFieldItem
component use a conditional to check if the selected value is equal than the item name:
export function RadioFieldItem({ value, isDisabled = false, onChange, selected }) {
const [id, setId] = React.useState(generateId());
const { activeIndex, setActiveIndex } = React.useContext(RadioFieldContext);
const isRadioSelected = (value: string | undefined): boolean =>
activeIndex === value;
const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
setActiveIndex &&
setActiveIndex((prevState) => {
onChange && onChange(e);
return e.target.value;
});
};
return (
<div>
<input
type="radio"
name={id}
id={id}
value={value}
checked={selected==value}
onChange={isDisabled ? undefined : handleChange}
/>
<label htmlFor={id}>{capitalizeFirstLetter(value)}</label>
</div>
);
}
CodePudding user response:
Yes, you can get it going, but the approach you're taking isn't the best. You're effectively storing two copies of the selected value - once in the RadioFieldContext
, and once in the local state.
The reason it works with they key
property is that it forces the RadioField
component to rerender every time the key changes, so that will internally rebuild the context object, and update the activeIndex
property.
A better solution would be to only have a single source of truth - the context (RadioField
). Then, change the context value with the buttons, and read the context value to see what is selected. Here's a demo using this solution.