Reputation: 1630
I have a Material UI Autocomplete combo-box child component class that fetches results as the user types:
...
fetchIngredients(query) {
this.sendAjax('/getOptions', {
data: {
q: query
}
}).then((options) => {
this.setState({
options: options
});
});
}
...
<Autocomplete
options={this.state.options}
value={this.state.value}
onChange={(e, val) => {
this.setState({value: val});
}}
onInputChange={(event, newInputValue) => {
this.fetchIngredients(newInputValue);
}}
renderInput={(params) => {
// Hidden input so that FormData can find the value of this input.
return (<TextField {...params} label="Foo" required/>);
}}
// Required for search as you type implementations:
// https://mui.com/components/autocomplete/#search-as-you-type
filterOptions={(x) => x}
/>
...
This child component is actually rendered as one of many in a list by its parent. Now, say I want the parent component to be able to set the value of each autocomplete programmatically (e.g., to auto-populate a form). How would I go about this?
I understand I could lift the value
state up to the parent component and pass it as a prop, but what about the this.state.options
? In order to set a default value of the combo-box, I'd actually need to also pass a single set of options such that value
is valid. This would mean moving the ajax stuff up to the parent component so that it can pass options
as a prop. This is starting to get really messy as now the parent has to manage multiple sets of ajax state for a list of its Autocomplete children.
Any good ideas here? What am I missing? Thanks in advance.
Upvotes: 0
Views: 1750
Reputation: 1183
If these are children components making up a form, then I would argue that hoisting the value state up to the parent component makes more sense, even if it does require work refactoring. This makes doing something with the filled-in values much easier and more organized.
Then in your parent component, you have something like this:
constructor(props) {
super(props);
this.state = {
values: [],
options: []
};
}
const fetchIngredients = (query, id) => {
this.sendAjax('/getOptions', {
data: {
q: query
}
}).then((options) => {
this.setState(prevState => {
...prevState,
[id]: options
});
});
}
const setValue = (newValue, id) => {
this.setState(prevState => {
...prevState,
[id]: newValue
};
}
render() {
return (
<>
...
{arrOfInputLabels.map((label, id) => (
<ChildComponent
id={id}
key={id}
value={this.state.values[id]}
options={this.state.options[id]}
fetchIngredients={fetchIngredients}
labelName={label}
/>
)}
...
</>
Upvotes: 1