Maybe I'm missing something, but from what I can tell the way that used to work to set the initial value of the select component does not work anymore in version 2.0. Here's what used to work (simplified for readability):
<ReactSelect
value={field.value}
options={field.options.map((option) => ({
...option,
label: option.name,
value: option.name,
clearableValue: true
}))}
/>
In the above example the field.value was a string value coming back from the server that matched the name of one of the options.
Is it no longer possible to set the initial value (and all subsequent values) with a string? That was a very nice feature and I would like to make a request for it to make a comeback if it's no longer available. If it's still there, can someone show me the light? I can't seem to get it working with v2.
I ran into this as well. The workaround is to pass the full option object and not just the string value, for example: value: { label: 'foo', value: 'bar' }.
Not sure if it's a bug or not, but it'd be convenient to set the value just using a string.
That being said I've spent the last two weeks building a reasonably advanced searching and filtering solution all powered by react-select v2 beta, and have run into almost zero issues. Reading through the source code is a nice experience as well, super well factored. Thanks @JedWatson and friends!
Thanks for the reply @billmers.
I've noticed that passing in the object works as well, but that means that instead of using a simple string value (which is what I assume most people will use to store values as when passing data between the client and the server) we need to first lookup the proper object in the options array and then pass in a reference to that. It's not the end of the world, but it's definitely not as convenient as using the string value.
Hopefully this will make a comeback in V2.
The issue comes from cleanValue which only expects an array or an object. cleanValue is used get a value for comparing to determine which option is selected.
https://github.com/JedWatson/react-select/blob/94df8a7ac19ec76beb8c8ccbc7fbbde86f26b5fb/src/utils.js#L53-L61
I also second having the value string functionality. App went from:
value={this.state.contactInfoTypeCandidate}
to:
value={
this.state.contactInfoTypeCandidate && {
label: getEnumsAsSelectOptions({ enums: ContactInfoType }).find(
({ value }) => value === this.state.contactInfoTypeCandidate
).label,
value: this.state.contactInfoTypeCandidate,
}
}
Yeah, this is going to be the single biggest breaking issue for me in upgrading from v1, it should probably at least be mentioned in the upgrade guide.
+1
or be able to pass an incomplete object that refer to an option :
value={
{ value: 'stringValue' }
}
or more risky (no duplicate label)
value={ { label: 'label' } }
Just spent two hours debugging just to realize this was the issue. This is not even mentioned in the upgrade guide! I stumbled upon this only when I saw this type ValueType = OptionType | OptionsType | null | void in the reference.
Any guidance here? This seems to be a pretty important issue
Refactoring larger/older codebases to get rid of string values completely would be a huge task. I would also really like to see this supported.
Currently working around this by wrapping all our Select components from react-select in my own component and doing something like:
function EnhancedSelect({ value, options, ...props }) {
const cleanValue =
typeof value === 'string' && value.length
? options.find(option => option.value === value)
: value;
return <Select value={cleanValue} options={options} {...props} />
}
This is not ideal. But updating all locations where we rely on string values passed to react-select would be a massive task.
Would love to help land something for this in the API. Maybe options.find() can be used for this somewhere internally? Though I'm not happy with it because it could potentially impact performance if a lot of options are in the list.
But a big thank you for the detailed migration guide otherwise, upgrading a large codebase was fairly straightforward 馃憤
https://github.com/JedWatson/react-select/pull/3050 Aims to resolve this so feel free to chime in there.
This keeps coming up. Part of the problem is documentation, for sure, but if you still really want to use simple value I've created a wrapper. You can get it from npm or take a look at the source and grab whatever you want.
<SimpleValue options={[...]} value="blue">
{props => <Select {...props} />}
</SimpleValue>
valuedefaultValuegetOptionValueisMulti where value/defaultValue is a comma delimited stringconst getValue = (opts, val) => opts.find(o => o.value === val);
const MySelect = ({ value, ...props }) => (
<ReactSelect value={getValue(props.options, value)} {...props} />
);
Thanks for the update! Package seems to work just fine :)
However I wonder what the recommended approach is for Async selects. Because options is only available internally after the promise resolves you can't really wrap the Select in a SimpleValue.
Maybe simple values is a pattern you don't want to encourage but I don't really see a better way than working with primitive values when you're setting the value of a select from an API response
I don't understand why do you need an additional wrapper. Having an array with objects having label and value keys can be easily returned as string with the current version 2, without any additional component:
~jsx
const options = [
{label: 'Whatever', value: 'whatever'},
{label: 'Two', value: 2},
]
return (
options={options}
value={options.filter(({value}) => value === this.state.value)}
getOptionLabel={({label}) => label}
getOptionValue={({value}) => value}
onChange={({value}) => this.setState({value})}
/>
~
Doing it this way, in this.state.value we'll have the string (or number, or whichever value you have selected), instead of the entire object.
Edit: Please note that I've used label and value, as it's the default used by react-select, and also it's the one exemplified in the package linked by @jossmac. But you can use this approach for any kind of array if I'm not wrong.
@elboletaire you're absolutely right, the wrapper is unnecessary. I would much prefer consumers rolled their own solution.
For some context, I was getting pinged about the "simple value" issue at least once a week. We're not going to add it to core and a lot of folks didn't arrive at a solution like you have detailed above. It was getting noisy so I decided to just put together that package.
It's also worth mentioning that you'll run into some awkwardness with multi values and grouped options, so that was another reason to create a wrapper.
I have to admit that it took me a bit to get to that solution. Maybe the documentation could be improved adding this use-case, as it's a common one.
@elboletaire that's a great idea. Perhaps you could add something to the upgrade guide?
Yeah, where do you think should I fit it? I'm not sure if it should be before the New Components API, or after. Let me know the place and I'll try to do the PR during the day.
Umm, I think just before the "Prop Update Guide":
<!-- Filtering -->
<h2>Techniques</h2>
<h3>Simple Value</h3>
<p>Since the simple value property was removed... etc.</p>
<code>alternative solution</code>
<!-- Prop Update Guide -->
What do you think?
I'm ok with it, but only a bit concerned about its visibility. Although it will be better there, than nowhere.
@jossmac fair enough! What was the reason for moving away from simple values?
This took me way longer to figure out than it should of :-)
I think documentation could be improved to make it really clear that value is expecting the entire object of the selected choice from options
For anyone else struggling with it @jossmac suggested solution pointed me in the right direction:
const getValue = (opts, val) => opts.find(o => o.value === val);
const MySelect = ({ value, ...props }) => (
<ReactSelect value={getValue(props.options, value)} {...props} />
);
value={options.filter(({value}) => value === this.state.value)}
I don't understand why do you need an additional wrapper. Having an array with objects having
labelandvaluekeys can be easily returned as string with the current version 2, without any additional component:const options = [ {label: 'Whatever', value: 'whatever'}, {label: 'Two', value: 2}, ] return ( <ReactSelect isMulti={false} options={options} value={options.filter(({value}) => value === this.state.value)} getOptionLabel={({label}) => label} getOptionValue={({value}) => value} onChange={({value}) => this.setState({value})} />Doing it this way, in
this.state.valuewe'll have the string (or number, or whichever value you have selected), instead of the entire object.Edit: Please note that I've used
labelandvalue, as it's the default used by react-select, and also it's the one exemplified in the package linked by @jossmac. But you can use this approach for any kind of array if I'm not wrong.
This is how it would ideally work if isMulti is true
const options = [
{label: 'Whatever', value: 'whatever'},
{label: 'Two', value: 2},
]
return (
<ReactSelect
isMulti={true}
options={options}
value={options.filter(({value}) => this.state.values.includes(value))}
getOptionLabel={({label}) => label}
getOptionValue={({value}) => value}
onChange={({value}) => this.setState({value})}
/>
I fixed this problem by passing a array with just one string:
<select defaultValue={[currentValueStr]} /> ...
According to the note block here: https://reactjs.org/docs/forms.html#the-select-tag
Most helpful comment
Just spent two hours debugging just to realize this was the issue. This is not even mentioned in the upgrade guide! I stumbled upon this only when I saw this
type ValueType = OptionType | OptionsType | null | voidin the reference.