I'm learning react and I am stuck. I am trying to share a form between Edit and Create components. I am having a really hard time figuring out what I am doing wrong to initialize the values of the checked property for the radio group. After the page loads I can toggle the radio buttons. Initially, however, neither is checked.
I'm starting to think I am setting up my checked property incorrectly on the form.
Edit component (forms parent component):
class CompanyMasterEdit extends React.Component {
componentDidMount() {this.props.fetchCompany(this.props.match.params.companyId,this.props.match.params.companyName)}
onSubmit = (formValues) => { this.props.editCompany(this.props.match.params.companyId, formValues) }
render() {
return (
<div style={{ padding: 50 }}>
<h1 style={{ textAlign: "center" }}>Edit Company Master Record</h1>
<h5 style={{ textAlign: "center" }}>
<span style={{ color: "red" }}>*</span> indicates required field
</h5>
<CompanyMasterForm
initialValues={_.pick(
this.props.company,
"isKeyCompany",...
)}
onSubmit={this.onSubmit}
/>
const mapStateToProps = (state, ownProps) => {
return { company: state.companies[ownProps.match.params.companyId] }
}
export default connect(mapStateToProps, { fetchCompany, editCompany })( CompanyMasterEdit)
Form:
class CompanyMasterForm extends React.Component {
<form
className="ui form error"
onSubmit={this.props.handleSubmit(this.onSubmit)}
>
<Field
label="Is This a Key Company?"
component={RadioGroup}
name="isKeyCompany"
required={true}
options={[
{ title: "Yes", value: true },
{ title: "No", value: false },
]}
checked={this.props.initialValues.isKeyCompany}
// onClick={this.setIsKeyCompany}
//onClick={(e) => this.setState({ isKeyCompany: e.target.checked })}
onClick={() => {this.setState((prevState) => {return {checked: !this.props.initialValues.isKeyCompany,}})
}}
/>
<button className="ui button primary">Submit</button>
</form>
RadioButtonGroup as a separate component:
class RadioGroup extends React.Component {
render() {
return (
<div className={className}>
<div className="inline fields">
<div className={labelClassName}>
<label>{label}</label>
</div>
{options.map((o) => {
const isChecked = o.value ? "true" : "false"
console.log("o.value :", o.value)
return (
<label key={o.title}>
<input
type="radio"
{...input}
value={o.value}
checked={isChecked === input.value}
/>
{o.title}
</label>
)
})}
</div>
</div>
)
}
}
// const mapStateToProps = (state) => {
// console.log("radio group state : ", state)
// return { isKeyCompany: state.form.companyMasterForm.values.isKeyCompany }
// }
// export default connect(mapStateToProps)(RadioGroup)
// export default connect(null)(RadioGroup)
export default RadioGroup
I have a codesandbox up. I feel like I'm close and dancing all around it but I can't get it. Any help is appreciated.
The value of an option is text (input.value is text but o.value is boolean). The checked property is boolean. ===
is never going to be quite right unless you fix one of those things.
This change makes an option show up. Not that it's truly the right change. We probably should have a slightly more robust compare for the checked property.
checked={o.value == input.value}
It's currently boolean because you set it here
options={[
{ title: "Yes", value: true },
{ title: "No", value: false },
]}
+1 on the research from @Nikki9696, but the better solution is to leave your comparison using the strict ===
check and change the options config to have string values:
options={[
{ title: "Yes", value: 'true' },
{ title: "No", value: 'false' },
]}
that's because "true" != true
(the string value "true" is not equal to the boolean value true
, even with type-coercion). The same can be said for a comparison between "false"
and false
.
A couple of remarks:
name
prop. So we can just write a hardcoded string for one set of options.value
prop doesn't determine whether the radio button is active. This is done via checked
/ defaultChecked
instead. The value
prop is particularly useful if we have more than two options (to label each option).input
is doing in the last code example?"true"
and "false"
as string values, if there are only two possible values. In this case, a boolean ( true
or false
without the quotation marks) is more suitable. This is the simplest way to represent your state, and typos such as "True"
won't slip through the cracks (when you're using strings, such typos will go unnoticed).defaultChecked
instead of checked
, if you want the user to be able to toggle the checkbox after the page has loaded.Your RadioGroup component will look as follows:
class RadioGroup extends React.Component {
state = { isKeyCompany: true } // initial value
render() {
return (
<div className={className}>
<div className="inline fields">
<div className={labelClassName}>
{label /* note: not wrapped in `<label>...</label>`, because it’s not the description of one option, but rather of the entire set. */}
</div>
{options.map((o) => (
<label key={o.title}>
<input
type="radio"
name="isKeyCompany" // for example
checked={this.state.isKeyCompany === o.value} // or passed down via props
onChange={() => this.setState({ isKeyCompany: o.value }))
/>
{o.title}
</label>
))}
</div>
</div>
)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.