React JSX: выбор «выбранного» в выбранном параметре <select>


403

В компоненте React для <select>меню мне нужно установить selectedатрибут для опции, которая отражает состояние приложения.

В render(), то optionStateпередается от состояния владельца к компоненту SortMenu. Значения параметров передаются как propsиз JSON.

render: function() {
  var options = [],
      optionState = this.props.optionState;

  this.props.options.forEach(function(option) {
    var selected = (optionState === option.value) ? ' selected' : '';

    options.push(
      <option value={option.value}{selected}>{option.label}</option>
    );
  });

// pass {options} to the select menu jsx

Однако это вызывает синтаксическую ошибку при компиляции JSX.

Это избавляет от синтаксической ошибки, но, очевидно, не решает проблему:

var selected = (optionState === option.value) ? 'selected' : 'false';

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

Я также попробовал это:

var selected = (optionState === option.value) ? true : false;

<option value={option.value} {selected ? 'selected' : ''}>{option.label}</option>

Есть ли рекомендуемый способ решения этой проблемы?


Поднятие вопроса только за заголовок
Эрикджо

Ответы:


649

React автоматически распознает логические значения для этой цели, поэтому вы можете просто написать (примечание: не рекомендуется)

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

и он выведет «выбрано» соответственно.

Однако React делает это еще проще для вас. Вместо определения selectedкаждого параметра вы можете (и должны) просто написать value={optionsState}сам тег select :

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

Для получения дополнительной информации см. Тег React select doc .


56
В текущей версии React (0.9) установка выбранного атрибута для параметров не работает вообще. Вместо этого установите атрибут value в элементе select.
liammclennan

2
я загружаю данные с ajax.defaultValue не работает для меня. значение работает, но я не могу выбрать другой элемент в списке выбора. Список открывается, но когда я выбираю один из них, он выбирает значение элемента. Есть идеи?
user1924375

5
@ user1924375, вы должны использовать событие onChange onChange={this.handleSelect}и установить значение состояния для вашего компонента, например: 'handleSelect: function () {this.setState ({value: event.target.value});} `Это приведет к переопределению выбранного компонента с новым выбранный пункт. Надеюсь, это поможет вам.
funnydaredevil

1
Хотя это еще не задокументировано, valueопора для a <select>может быть массивом, если вы его multiselectвключили.
tirdadc

4
Скорее используйте defaultValueдля инициализации
dewwwald

70

Вы можете делать то, что предупреждает React, когда вы пытаетесь установить свойство «selected» для <option>:

Используйте defaultValueили valueреквизит на <select>вместо установки selectedна <option>.

Таким образом, вы можете использовать options.valueна defaultValueваш выбор


9
Если я все еще хочу указать опцию, которая в настоящее время выбрана, как бы я это сделал? Единственный способ, которым я в настоящее время могу фактически сохранить выбранную опцию (и сохранить состояние формы для будущего POSTing), это установить select = true. Я попытался установить значения по умолчанию и значения для элемента select, но это не отображается в представлении, если установить правильный параметр для выбранного в меню параметров. Любой совет?
Pied Pipes

4
Пример может быть ??
Синдзоу

1
У меня не работает: <select className = "form-control" value = "Mois">
Kuartz

2
defaultValue не работает с последней версией
Hos Mercury

18

Вот полное решение, которое включает в себя лучший ответ и комментарии под ним (что может помочь кому-то изо всех сил собрать все вместе):

ОБНОВЛЕНИЕ ДЛЯ ES6 (2019) - использование функций стрелок и разрушение объектов

в основном компоненте:

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

}

включенный компонент (который теперь является функционалом без сохранения состояния):

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

ПРЕДЫДУЩИЙ ОТВЕТ (используя bind):

в основном компоненте:

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

}

включенный компонент (который теперь является функционалом без сохранения состояния):

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

основной компонент поддерживает выбранное значение для фруктов (в состоянии), включенный компонент отображает элемент выбора, и обновления передаются обратно в основной компонент для обновления его состояния (которое затем возвращается к включенному компоненту для изменения выбранного значения).

Обратите внимание на использование свойства prop, которое позволяет вам объявлять один метод handleChange для других полей в той же форме независимо от их типа.


Обратите внимание, что строка в конструкторе this.handleChange.bind(this);должна быть this.handleChange = this.handleChange.bind(this);
Будет ли бритва

для тех из вас, кто любит меня, кто спрашивает себя, что означает ... responsejs.org/docs/jsx-in-depth.html#spread-attributes
talsibony

@talsibony - это действительно оператор распространения, но в моем примере кода это просто означает, что здесь нужно вставить какой-то другой код !
Энди Лоренц

@AndyLorenz Так что в этом случае я бы порекомендовал удалить его ... :) или просто написать комментарий, как // остальная часть вашего кода
talsibony

8

Вот последний пример того, как это сделать. От реагировать документы , плюс автоматически связывающий синтаксис метода "жирная стрелка".

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};
  }

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

  handleSubmit = (event) => {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
} 

4

Просто добавьте в качестве первого варианта вашего выбора тега:

<option disabled hidden value=''></option>

Это станет по умолчанию, и когда вы выберете действительный вариант будет установлен в вашем штате


1
***Html:***
<div id="divContainer"></div>

var colors = [{ Name: 'Red' }, { Name: 'Green' }, { Name: 'Blue' }];
var selectedColor = 'Green';

ReactDOM.render(<Container></Container>, document.getElementById("divContainer"));

var Container = React.createClass({
    render: function () {
        return (
        <div>            
            <DropDown data={colors} Selected={selectedColor}></DropDown>
        </div>);
    }
});

***Option 1:***
var DropDown = React.createClass(
{
    render: function () {
        var items = this.props.data;
        return (
        <select value={this.props.Selected}>
            {
                items.map(function (item) {
                    return <option value={item.Name }>{item.Name}</option>;
                })
            }
        </select>);
    }
});

***Option 2:***
var DropDown = React.createClass(
{
    render: function () {
        var items = this.props.data;
        return (
        <select>
            {
                items.map(function (item) {
                    return <option value={item.Name} selected={selectedItem == item.Name}>{item.Name}</option>;
                })
            }
        </select>);
    }
});

***Option 3:***
var DropDown = React.createClass(
    {
        render: function () {
            var items = this.props.data;
            return (
            <select>
                {
                    items.map(function (item) {

                                            if (selectedItem == item.Name)
                    return <option value={item.Name } selected>{item.Name}</option>;
                else
                    return <option value={item.Name }>{item.Name}</option>;
                    })
                }
            </select>);
        }
    });

1
Хотя никакого объяснения не было дано, оно на самом деле не было нужно. Многочисленные способы решения одной и той же проблемы были действительно полезными для понимания. Спасибо
DJ2

0

У меня была проблема с <select>тегами, которые не обновляются до правильных <option>при изменении состояния. Моя проблема заключалась в том, что если вы дважды рендеритесь подряд, первый раз без предварительного выбора, <option>а второй с одним, то<select> тег не обновляется при втором рендере, а остается по умолчанию первым.

Я нашел решение этого с помощью ссылок . Вам нужно получить ссылку на ваш <select>узел тега (который может быть вложен в некоторый компонент), а затем вручную обновить valueсвойство в нем, в componentDidUpdateхуке.

componentDidUpdate(){
  let selectNode = React.findDOMNode(this.refs.selectingComponent.refs.selectTag);
  selectNode.value = this.state.someValue;
}

0

Опубликовать аналогичный ответ для MULTISELECT / optgroups:

render() {
  return(
    <div>
      <select defaultValue="1" onChange={(e) => this.props.changeHandler(e.target.value) }>
        <option disabled="disabled" value="1" hidden="hidden">-- Select --</option>
        <optgroup label="Group 1">
          {options1}
        </optgroup>
        <optgroup label="Group 2">
          {options2}
        </optgroup>
      </select>
    </div>
  )
}

0

У меня есть простое решение, следуя основному HTML.

<input
  type="select"
  defaultValue=""
  >
  <option value="" disabled className="text-hide">Please select</option>
  <option>value1</option>
  <option>value1</option>
</input>

.text-hide это класс начальной загрузки, если вы не используете загрузчик, вот вы:

.text-hide {
  font: 0/0 a;
  color: transparent;
  text-shadow: none;
  background-color: transparent;
  border: 0;
}

-1

Я обошел похожую проблему, установив defaultProps:

ComponentName.defaultProps = {
  propName: ''
}

<select value="this.props.propName" ...

Так что теперь я избегаю ошибок при компиляции, если моя опора не существует до монтирования.


Это действительно не решает проблему. Вы получите следующее: Предупреждение: Ошибка типа проп: Вы предоставили valueреквизит для поля формы без onChangeобработчика. Это сделает поле только для чтения. Если поле должно быть изменчивым, используйте defaultValue. В противном случае, установите либо onChangeили readOnly.
Джейсон Райс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.