react-select: [V2] Setting initial value of select component with a string value no longer works

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.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 9
  • Comments: 23 (5 by maintainers)

Commits related to this issue

Most upvoted comments

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.

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:

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.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.

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!

Any guidance here? This seems to be a pretty important issue

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 label and value keys 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.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.

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})}
  />

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.

Usage

<SimpleValue options={[...]} value="blue">
  {props => <Select {...props} />}
</SimpleValue>

Supports

  • simple value
  • simple defaultValue
  • grouped options
  • custom getOptionValue
  • isMulti where value/defaultValue is a comma delimited string

Trivial Alternative

const getValue = (opts, val) => opts.find(o => o.value === val);

const MySelect = ({ value, ...props }) => (
  <ReactSelect value={getValue(props.options, value)} {...props} />
);

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 👍