I'm calling a custom component in my redux-form.
<Field name="myField" component={SiteProjectSelect}/>
This component is a combination of two combo boxes. The second box is dependant on the value of the first on - ie depending on what site you select, you can choose from a list of projects. What I'd like to do is get the form to receive the selected site and the selected projects. However, I'm not sure how to pass the values to the redux-form.
class SiteProjectSelect extends Component {
constructor() {
super();
this.state = {
selectedSite: null,
selectedProject: null,
};
}
handleSiteSelection = selectedSite => {
console.log(selectedSite)
this.setState({ selectedSite, selectedProject: null });
};
handleProjectSelection = selectedProject => {
this.setState({ selectedProject });
this.props.input.onChange(selectedProject.value);
};
render() {
const selectedRow = this.state.selectedSite ? projects.find((node) => node.site === this.state.selectedSite.value) : "";
const filteredProjectOptions = selectedRow ? selectedRow.projects.map(project => ({ value: project, label: project })) : []
return (
<div {...this.props} >
<label>Site</label>
<div style={{ marginBottom: '20px' }} >
<Select
name="site"
value={this.state.selectedSite}
onChange={this.handleSiteSelection}
options={siteOptions}
isSearchable
/>
</div>
<div style={{ marginBottom: '20px' }} >
<label>Project</label>
<Select
name="project"
value={this.state.selectedProject}
onChange={this.handleProjectSelection}
options={filteredProjectOptions}
isMulti
isSearchable
closeMenuOnSelect={false}
/>
</div>
</div>
);
}
}
I did finally figure it out. For anyone else who stumbles across this, here's what I needed to know. To use a custom component,
onChange
prop to set the new value of the Field. You do this by calling the onChange
function, this.props.input.onChange(your-components-new-value-here)
when you need to change the value of the component and passing it the new value. value
prop: this.props.input.value
. So, wherever in the render function for your component you need to pass/display the current value of your component, use the value
prop. It has to be the value
prop and not another variable such as what you passed to your onChange function. What this does is give control of what's displayed to the state of your redux-form which the value
prop is tied to. Why is this useful? For example, you could take the user to a form review page when they're done and then back to the form if the user wants to make some more changes. How would redux-form know how to repopulate all of what's displayed without getting the user to fill in the form again? Because the display is dependant on the state, not user input! Took me a while to make sense of all this!! In my example, where I was using two react-select
components, one of which was dependant on the other, I ended up having to use the Fields component which allowed me to have two Fields in my component rather than just the one. Once I implemented this, it also became evident that I didn't need to have a separate state within my component as the value of both Fields is always accessible via the value
prop for each of them. So, yes, I could have just used a stateless function after all!
I call my component with:
<Fields names={["site", "projects"]} component={SiteProjectSelect} />
My final working component:
class SiteProjectSelect extends Component {
handleSiteSelection = selectedSite => {
this.props.site.input.onChange(selectedSite);
this.props.projects.input.onChange(null);
};
handleProjectSelection = selectedProjects => {
this.props.projects.input.onChange(selectedProjects);
};
renderSite = () => {
const {
input: { value },
meta: { error, touched }
} = this.props.site;
return (
<div>
<label>Site</label>
<div style={{ marginBottom: '20px' }}>
<Select
name="site"
value={value}
onChange={this.handleSiteSelection}
options={siteOptions}
isSearchable
/>
</div>
<div className="red-text" style={{ marginBottom: '20px' }}>
{touched && error}
</div>
</div>
);
};
renderProjects = () => {
var {
input: { value },
meta: { error, touched }
} = this.props.projects;
const selectedSite = this.props.site.input.value;
const selectedRow = selectedSite
? projects.find(node => node.site === selectedSite.value)
: '';
const filteredProjectOptions = selectedRow
? selectedRow.projects.map(project => ({
value: project,
label: project
}))
: [];
return (
<div>
<div style={{ marginBottom: '20px' }}>
<label>Projects</label>
<Select
name="projects"
value={value}
onChange={this.handleProjectSelection}
options={filteredProjectOptions}
isMulti
isSearchable
closeMenuOnSelect={false}
/>
</div>
<div className="red-text" style={{ marginBottom: '20px' }}>
{touched && error}
</div>
</div>
);
};
render() {
return (
<div>
{this.renderSite()}
{this.renderProjects()}
</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.