Reputation: 121
Use the defaultValue or value props on instead of setting selected on .
<select defaultValue="react">
<option value="react">React</option>
<option value="angular">Angular</option>
</select>
defaultValue would work with the above select tag. However, it does not seem to work with options generated by loop.
<select defaultValue={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
Probably options not fully been set when defaultValue was declared?
I could do manual assigning in componentDidUpdate()
and onChange
event.
But my question is - Is there any cleaner(better) way to solve it?
Thanks.
Upvotes: 12
Views: 12830
Reputation: 1
You can do something like this, React will complain because it uses value instead of selected for consistency across the form components, more information.
const {useState} = React;
const Example = ({title}) => {
const [states, setStates] = useState({
selected: "Florida",
values: [{name: "Alabama", code: "AL"}, {name: "Hawai", code: "HW"},{name: "Florida", code: "FL"}]
});
return (
<select
className="w-full"
onChange={(e: any) => {
setStates({
...states,
selected: e.target.value,
});
}}
>
{states.values.map((state) => (
<option
value={state.name}
key={state.name}
selected={state.name === states.selected}
>
{state.name}
</option>
))}
</select>
);
};
ReactDOM.createRoot(
document.getElementById("root")
).render(
<Example title="Example using Hooks:" />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
Upvotes: 0
Reputation: 373
The best solution that I could find is to set key
attribute the same as defaultValue
so it will be a different element.
Aftermaths are not researched by me but I believe it should be okay.
Upvotes: 0
Reputation: 633
This is old, but since answer #1 is related to a controlled Select
and the question seems to be related to uncontrolled Select
I think is worth to leave some lines for future readers:
The problem is that for uncontrolled
components React needs to know what are the options
before the first render, since from that moment the defaultValue
won't override the current value of the Select
. This means that if you render the Select
before the options
it won't know what to select.
You can solve the problem avoiding the render
before the options
are available:
const RenderConditionally = ({ options, selected }) => options.length > 0 ? (
<select defaultValue={selected}>
{options.map(item => (
<option key={item.id} value={item.value}>{item.label}</option>
))}
</select>
) : null;
Or without ternary if you desire:
const RenderConditionally = ({ options, selected }) => {
if (options.length === 0) {
return null;
}
return (
<select defaultValue={selected}>
{options.map(item => (
<option key={item.id} value={item.value}>{item.label}</option>
))}
</select>
);
};
Upvotes: 6
Reputation: 3583
For users running into this issue, you can get the desired functionality by using the value
prop, instead of defaultValue
, e.g.:
<select value={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
Upvotes: 4
Reputation: 12862
Most probably you have something wrong with option_id
and options
arrays structure, or selectedOptionId
variable. The way you build your select component is ok.
I've made a fiddle where this code works fine:
render: function() {
let option_id = [0, 1];
let options = [{name: 'a'}, {name: 'b'}];
let selectedOptionId = 1
return (
<select defaultValue={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
)
}
Upvotes: 0