React JSX: wybranie „selected” na wybranej opcji <select>

402

W komponencie React dla <select>menu muszę ustawić selectedatrybut w opcji odzwierciedlającej stan aplikacji.

W render()The optionStateprzechodzi od właściciela państwowego do składnika SortMenu. Wartości opcji są przekazywane propsod 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

Wywołuje to jednak błąd składniowy kompilacji JSX.

W ten sposób pozbywasz się błędu składniowego, ale oczywiście nie rozwiązuje problemu:

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

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

Próbowałem także:

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

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

Czy istnieje zalecany sposób rozwiązania tego problemu?

Cantera
źródło
Głosowanie pytania tylko o tytuł
ericgio

Odpowiedzi:

647

React automatycznie rozumie booleany w tym celu, więc możesz po prostu pisać (uwaga: niezalecane)

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

i odpowiednio wyświetli „wybrane”.

Jednak React sprawia, że ​​jest to jeszcze łatwiejsze. Zamiast definiować selectedkażdą opcję, możesz (i powinieneś) po prostu napisać value={optionsState}na samym tagu select :

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

Aby uzyskać więcej informacji, zobacz dokument React select tag .

Sophie Alpert
źródło
56
Przy obecnej wersji React (0.9) ustawienie wybranego atrybutu na opcjach w ogóle nie działa. Zamiast tego ustaw atrybut wartości na elemencie select.
liammclennan
2
ładuję dane za pomocą ajax.defaultValue nie działa dla mnie. wartość działa, ale nie mogę wybrać innego elementu na liście wyboru. Lista się otwiera, ale kiedy wybieram jeden z nich, wybieram wartość elementu. Masz pomysł?
user1924375
5
@ user1924375 powinieneś użyć zdarzenia onChange onChange={this.handleSelect}i ustawić wartość stanu dla swojego komponentu, na przykład: „handleSelect: function () {this.setState ({value: event.target.value});}„ Spowoduje to ponowne wysłanie wybranego komponentu z nowym wybrany przedmiot. Mam nadzieję, że to ci pomoże.
funnydaredevil
1
Chociaż nie jest to jeszcze udokumentowane, valuerekwizyt na a <select>może być tablicą, jeśli multiselectwłączyłeś.
tirdadc
4
Raczej użyj defaultValuedo inicjalizacji
dewwwald
70

Możesz zrobić to, co ostrzega React, próbując ustawić właściwość „selected” <option>:

Użyj defaultValuelub valuerekwizyty na <select>zamiast ustawienie selectedna <option>.

Tak, można używać options.valuena defaultValuetwoich wybierz

Philippe Santana
źródło
9
Jeśli nadal chcę wskazać aktualnie wybraną opcję, jak miałbym to zrobić? Jedynym sposobem, w jaki aktualnie jestem w stanie utrzymać wybraną opcję (i zachować stan formularza do przyszłego testu POST), jest ustawienie select = true. Próbowałem ustawić defaultValue i rekwizyty wartości elementu select, ale nie wyświetla się to w widoku przez ustawienie prawidłowej opcji na wybraną w menu opcji. Jakakolwiek rada?
The Pied Pipes
4
Przykład może?
shinzou,
1
Nie działa dla mnie: <select className = "form-control" wartość = "Mois">
Kuartz
2
defaultValue nie działa z najnowszą wersją
Hos Mercury
18

Oto kompletne rozwiązanie, które zawiera najlepszą odpowiedź i komentarze poniżej (które mogą pomóc komuś, kto stara się to wszystko ułożyć):

AKTUALIZACJA DLA ES6 (2019) - przy użyciu funkcji strzałek i niszczenia obiektów

w głównym składniku:

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

}

dołączony komponent (który jest teraz funkcją bezstanową):

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

POPRZEDNIA ODPOWIEDŹ (używając binda):

w głównym składniku:

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

}

dołączony komponent (który jest teraz funkcją bezstanową):

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

główny składnik zachowuje wybraną wartość dla owoców (w stanie), dołączony składnik wyświetla wybrany element i aktualizacje są przekazywane z powrotem do głównego składnika w celu zaktualizowania jego stanu (który następnie zapętla się z powrotem do dołączonego składnika, aby zmienić wybraną wartość).

Zwróć uwagę na użycie nazwy prop, która pozwala zadeklarować pojedynczą metodę handleChange dla innych pól w tym samym formularzu, niezależnie od ich typu.

Andy Lorenz
źródło
Zauważ, że linia w konstruktorze this.handleChange.bind(this);powinna być this.handleChange = this.handleChange.bind(this);
Will Shaver,
dla tych z Was, podobnie jak ja, którzy je pytając siebie Co do ... środki: reactjs.org/docs/jsx-in-depth.html#spread-attributes
talsibony
@talsibony - to rzeczywiście operator rozprzestrzeniania, ale w moim przykładowym kodzie oznacza to po prostu wstawienie tutaj innego kodu !
Andy Lorenz,
@AndyLorenz Więc w takim przypadku polecam go usunąć ... :) lub po prostu napisz komentarz jak // reszta kodu
talsibony
8

Oto najnowszy przykład tego, jak to zrobić. Od reagują docs oraz automatycznie wiążącą składnię metody „fat-arrow”.

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>
    );
  }
} 
Rahil Ahmad
źródło
4

Po prostu dodaj jako pierwszą opcję wybranego tagu:

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

Stanie się to domyślne, a kiedy wybierzesz prawidłową opcję, zostanie ustawiona w twoim stanie

Pietro Allievi
źródło
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>);
        }
    });
muthuvel
źródło
1
Chociaż nie podano żadnego wyjaśnienia, jedno nie było tak naprawdę potrzebne. Wiele sposobów podejścia do tego samego problemu było bardzo pomocne. Dzięki
DJ2,
0

Mam problem z tym, że <select>tagi nie aktualizują się poprawnie <option>po zmianie stanu. Mój problem zdawał się polegać na tym, że jeśli renderujesz dwa razy w krótkich odstępach czasu, za pierwszym razem bez uprzednio zaznaczonego, <option>ale za drugim razem z jednym, wtedy <select>znacznik nie aktualizuje się przy drugim renderowaniu, ale pozostaje domyślnie pierwszy.

Znalazłem rozwiązanie tego problemu za pomocą referencji . Musisz uzyskać odniesienie do <select>węzła znacznika (który może być zagnieżdżony w jakimś komponencie), a następnie ręcznie zaktualizować valuewłaściwość na nim, w punkcie componentDidUpdatezaczepienia.

componentDidUpdate(){
  let selectNode = React.findDOMNode(this.refs.selectingComponent.refs.selectTag);
  selectNode.value = this.state.someValue;
}
William Myers
źródło
0

Publikowanie podobnej odpowiedzi dla 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>
  )
}
daino3
źródło
0

Mam proste rozwiązanie jest zgodne z podstawowym HTML.

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

.text-hide jest klasą bootstrap, jeśli nie używasz bootstrap, oto jesteś:

.text-hide {
  font: 0/0 a;
  color: transparent;
  text-shadow: none;
  background-color: transparent;
  border: 0;
}
Fin
źródło
-1

Rozwiązałem podobny problem, ustawiając defaultProps:

ComponentName.defaultProps = {
  propName: ''
}

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

Więc teraz unikam błędów przy kompilacji, jeśli mój rekwizyt nie istnieje przed montażem.

Matt Saunders
źródło
To naprawdę nie rozwiązuje problemu. Otrzymasz to: Ostrzeżenie: Nieudany typ rekwizytu: valuePodałeś rekwizyt do pola formularza bez onChangemodułu obsługi. Spowoduje to renderowanie pola tylko do odczytu. Jeśli pole powinno być zmienne, użyj defaultValue. W przeciwnym razie, należy ustawić albo onChangealbo readOnly.
Jason Rice