React JSX: selecting "selected" on selected <select> option

Here is a complete solution which incorporates the best answer and the comments below it (which might help someone struggling to piece it all together):

UPDATE FOR ES6 (2019) - using arrow functions and object destructuring

in main component:

class ReactMain extends React.Component {

  constructor(props) {
    super(props);
    this.state = { fruit: props.item.fruit };
  }

  handleChange = (event) => {
    this.setState({ [event.target.name]: event.target.value });
  }

  saveItem = () => {
    const item = {};
    item.fruit = this.state.fruit;
    // do more with item object as required (e.g. save to database)
  }

  render() {
    return (
      <ReactExample name="fruit" value={this.state.fruit} handleChange={this.handleChange} />
    )
  }

}

included component (which is now a stateless functional):

export const ReactExample = ({ name, value, handleChange }) => (
  <select name={name} value={value} onChange={handleChange}>
    <option value="A">Apple</option>
    <option value="B">Banana</option>
    <option value="C">Cranberry</option>
  </select>
)

PREVIOUS ANSWER (using bind):

in main component:

class ReactMain extends React.Component {

  constructor(props) {
    super(props);
    // bind once here, better than multiple times in render
    this.handleChange = this.handleChange.bind(this);
    this.state = { fruit: props.item.fruit };
  }

  handleChange(event) {
    this.setState({ [event.target.name]: event.target.value });
  }

  saveItem() {
    const item = {};
    item.fruit = this.state.fruit;
    // do more with item object as required (e.g. save to database)
  }

  render() {
    return (
      <ReactExample name="fruit" value={this.state.fruit} handleChange={this.handleChange} />
    )
  }

}

included component (which is now a stateless functional):

export const ReactExample = (props) => (
  <select name={props.name} value={props.value} onChange={props.handleChange}>
    <option value="A">Apple</option>
    <option value="B">Banana</option>
    <option value="C">Cranberry</option>
  </select>
)

the main component maintains the selected value for fruit (in state), the included component displays the select element and updates are passed back to the main component to update its state (which then loops back to the included component to change the selected value).

Note the use of a name prop which allows you to declare a single handleChange method for other fields on the same form regardless of their type.


React makes this even easier for you. Instead of defining selected on each option, you can (and should) simply write value={optionsState} on the select tag itself:

<select value={optionsState}>
  <option value="A">Apple</option>
  <option value="B">Banana</option>
  <option value="C">Cranberry</option>
</select>

For more info, see the React select tag doc.

Also, React automatically understands booleans for this purpose, so you can simply write (note: not recommended)

<option value={option.value} selected={optionsState == option.value}>{option.label}</option>

and it will output 'selected' appropriately.


You could do what React warns you when you try to set the "selected" property of the <option>:

Use the defaultValue or value props on <select> instead of setting selected on <option>.

So, you can use options.value on the defaultValue of your select