I'm working on a form in which one of the input items will be a select list. I am trying to implement the form by using reusable components. The hierarchy is this:
<SignupForm>
<CountrySelectList>
<SelectList>
I am able to get the select list to render, but I am not sure how to pass the needed props
to the child componets in order to bind the selection from the drop down list? Here are the components (with some form fields removed for brevity).
SignupForm
class SignupForm extends React.Component {
constructor(props) {
super(props);
this.state = {
country: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
handleSubmit(event) {
event.preventDefault();
let formData = new FormData();
formData.append("Country", this.state.country);;
fetch("api/account/signup", {
method: "POST",
body: formData })
.then(response => response.json())
.then(data => console.log(data));
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<CountrySelectList name="country" value={this.state.country} onChange={this.handleChange} />
<SubmitButton btnText="Submit"/>
</form>
);
}
}
export default SignupForm;
CountrySelectList
class CountrySelectList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: []
};
}
async componentDidMount() {
try {
const response = await fetch('api/location/countries');
const json = await response.json();
this.setState({
data: json,
isLoaded: true
});
} catch (error) {
console.log(error);
}
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <LoadingSpinner/>;
} else {
return (
<SelectListGroup>
<Label label="country" title="Country"/>
<SelectList data={data} value={this.props.value} onChange={this.props.onChange} />
</SelectListGroup>
);
}
}
}
export default CountrySelectList;
SelectList
export default function SelectList({ data, value, onChange, addClass="" }) {
return (
<select
value={value}
className={`form-select ${addClass}`}
onChange={onChange}>
{data.map((data, index) => (
<option key={index} value={data.value}>
{data.text}
</option>
))}
</select>
);
}
CodePudding user response:
This answer has a good explanation of getting data from forms and their component parts.
Get form data in ReactJS
You're kind of doing the same job twice by saving the selection as state
and using form
-> submit
.
If you give your select
a name
attribute, then in the handleSubmit
function, the event parameter will contain a named element that you can get the value from.
<select name='country' ...
Then the function can use
const handleSubmit = (event) => {
console.log(event.target.country.value);
}
The onSubmit event of the form carries all the info, you just have to name the elements.