Reputation: 87
I am trying to troubleshoot a problem which I am unable to solve. The issue is that I have a dropdown box with a select tag with some menu items in it. When I click one of the menu items the value is not appearing in the select box and its just empty. However when I console log the selected item I can see what I am selecting which is the menu item. Heres the code:
<Select labelId="demo-simple-select-label" id="demo-simple-select" value={selectedMake} onChange={handleMake}>
{console.log(makes)}
{makes &&
makes.map((select, key) => (
<MenuItem key={key} value={select}>
{console.log(select)}
{select.name}
</MenuItem>
))}
</Select>
If you're wondering what is "makes", it is just this:
(3) [{…}, {…}, {…}]
0: {name: "Honda", id: "5de9c553bce4b703a335c204"}
1: {name: "Toyota", id: "5e4dfbee2d445b7525414c1f"}
2: {name: "Suzuki", id: "5e4e00732d445b7525414c46"}
Im not sure why the when Honda is selected for example it is not showing in the box. I reckon it might be something to do with the id. Do let me know how to solve this problem.
This is the handleMake function as well, it is a function that is passed in as a prop from another file:
handleMake = (event) => {
this.setState({
selectedMake: event.target.value.name,
selectedMakeId: event.target.value.id,
});
};
Upvotes: 1
Views: 5567
Reputation: 202605
Objects cannot be the value of a select option, it must be a non-object value. In your you are setting the option value to the entire "makeobject, but setting the
Selectvalue to *just* the make's
name` property, which will never match.
handleMake = (event) => {
this.setState({
selectedMake: event.target.value.name, // <-- make's name
selectedMakeId: event.target.value.id,
});
};
...
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={selectedMake} // <-- only a make's name
onChange={handleMake}
>
{makes.map((select, key) => (
<MenuItem key={key} value={select}> // <-- entire make object!
{select.name}
</MenuItem>
))}
</Select>
I suggest storing the selected index or id
in state instead.
There is no need to duplicate so much data into state as you can easily derive the car make and id from a stored array index or search using the id. If you used data from one of the make objects then you'd need to search the makes
array each time (O(n)
linear time) to find a match, but by using the index you can get just the make object needed in O(1)
constant time.
handleMake = (event) => {
this.setState({
selectedMake: event.target.value,
});
};
...
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.state.selectedMake} // <-- value is "index"
onChange={this.handleMake}
>
{makes.map((make, index) => (
<MenuItem key={index} value={index}> // <-- pass index as "value"
{make.name}
</MenuItem>
))}
</Select>
To handle using the selectedMake
, for example, if selectedMake
=== 0
:
makes[selectedMake] // { name: "Honda", id: "5de9c553bce4b703a335c204"}
Example Component
function App() {
const [selectedMake, setSelectedMake] = useState(-1);
const changeHandler = (e) => setSelectedMake(e.target.value);
useEffect(() => {
console.log(selectedMake, makes[selectedMake]);
}, [selectedMake]);
return (
<div className="App">
<select value={selectedMake} onChange={changeHandler}>
<option disabled value={-1}>
Make
</option>
{makes.map((make, i) => (
<option key={make.id} value={i}>
{make.name}
</option>
))}
</select>
</div>
);
}
Upvotes: 1