React JSX: Как выбрать "selected" для выбранного элемента <select>
Проблема с атрибутом selected в компоненте React для
В компоненте React для меню <select>, мне необходимо установить атрибут selected на элементе <option>, который соответствует состоянию приложения.
В методе 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>
);
});
// передаем {options} в JSX меню select
}
Однако это вызывает синтаксическую ошибку при компиляции 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>
Существуют ли рекомендуемые способы решения данной проблемы?
5 ответ(ов)
Вы можете сделать то, о чем React предупреждает, когда вы пытаетесь установить свойство selected у <option>:
Используйте свойства
defaultValueилиvalueу<select>, вместо того чтобы устанавливатьselectedу<option>.
Таким образом, вы можете использовать options.value в качестве defaultValue вашего <select>.
Вот полное решение, которое включает в себя лучший ответ и комментарии ниже него (что может помочь тем, кто пытается собрать всё воедино):
ОБНОВЛЕНИЕ ДЛЯ 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;
// делаем больше с объектом item по необходимости (например, сохранить в базе данных)
}
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">Яблоко</option>
<option value="B">Банан</option>
<option value="C">Клюква</option>
</select>
)
ПРЕДЫДУЩИЙ ОТВЕТ (с использованием bind):
В главном компоненте:
class ReactMain extends React.Component {
constructor(props) {
super(props);
// связываем один раз здесь, лучше, чем множество раз в 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;
// делаем больше с объектом item по необходимости (например, сохранить в базе данных)
}
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">Яблоко</option>
<option value="B">Банан</option>
<option value="C">Клюква</option>
</select>
)
Главный компонент поддерживает выбранное значение для фрукта (в состоянии), включённый компонент отображает элемент выбора и обновления передаются обратно в главный компонент для обновления его состояния (что затем возвращается в включённый компонент для изменения выбранного значения).
Обратите внимание на использование пропса name, который позволяет объявлять один метод handleChange для других полей на той же форме независимо от их типа.
Основная идея - Управляемый компонент
Вы хотите настроить "Управляемый компонент". Для этого вам необходимо установить значение на элементе, а также обработать событие изменения, чтобы обновить значение.
https://reactjs.org/docs/forms.html#controlled-components
Примеры
https://codepen.io/codyswartz/pen/QWqYNrY
Простой пример функционального компонента Select
Этот пример также включает значение по умолчанию и затем делает его серым.
const defaultSelectValue = "Выберите фрукт"
const SelectExample = () => {
const [selected, setSelected] = useState(defaultSelectValue)
return (
<>
<label htmlFor="fruits">Фрукты</label>{' '}
<select
id="fruits"
name="fruits"
defaultValue={selected}
style={{ color: selected === defaultSelectValue ? "gray" : "black" }}
onChange={e => setSelected(e.target.value)}
>
<option>{defaultSelectValue}</option>
<option>Банан</option>
<option>Яблоко</option>
<option>Апельсин</option>
</select>
<h2>Выбрано: {selected}</h2>
</>
)
}
// Использование
<SelectExample />
Динамический повторно используемый пример с умолчанием
Этот пример принимает коллекцию строк, используя первую как значение по умолчанию.
const SelectExample = ({ name, items }) => {
const defaultSelectValue = items[0]
const [selected, setSelected] = useState(defaultSelectValue)
return (
<>
<label htmlFor={name}>{name}</label>{' '}
<select
id={name}
name={name}
defaultValue={selected}
style={{ color: selected === defaultSelectValue ? "gray" : "black" }}
onChange={e => setSelected(e.target.value)}
>
{items.map(item => (
<option key={item} value={item}>
{item}
</option>
))}
</select>
<h2>Выбрано: {selected}</h2>
</>
)
}
// Использование
<SelectExample
name="фрукты"
items={['Выберите фрукт', 'Банан', 'Яблоко', 'Апельсин']}
/>
Просто добавьте в качестве первого варианта в ваш тег <select> следующий код:
<option disabled hidden value=''></option>
Это станет значением по умолчанию, и когда вы выберете действительный вариант, он будет установлен в ваше состояние.
В вашем коде есть несколько вариантов реализации компонента DropDown, который отвечает за отображение выпадающего списка. Давайте рассмотрим их подробнее.
Вариант 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> ); } });В этом варианте используется атрибут
valueу элементаselect, который устанавливается в значение изprops.Selected. Это самый распространенный способ управления состоянием выбранного элемента для контролируемых компонентов в React.Вариант 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> ); } });Здесь используется атрибут
selectedдля каждой опции, однако это не самый лучший подход, так как он не соответствует концепции контролируемых компонентов в React. Лучше использовать атрибутvalueна уровнеselect, как в первом варианте.Вариант 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> ); } });Этот подход тоже не является лучшим способом, так как вы используете условную логику внутри метода
mapдля определения того, какая опция должна быть выбранной. Это может привести к нестабильному поведению и сложности в управлении состоянием.
Рекомендация
Наиболее корректный и рекомендуемый способ — использовать вариант 1, где вы управляете состоянием выбранного элемента через атрибут value на уровне select. Это соответствует лучшим практикам работы с контролируемыми компонентами в React и обеспечивает наибольшую предсказуемость поведения вашего компонента.
Как реализовать дебаунс?
Обнаружена ошибка: Невозможное нарушение: Неверный тип элемента: ожидался строковый тип (для встроенных компонентов) или класс/функция, но получен объект
Добавление тега script в React/JSX
"Не используйте Route или withRouter() вне Router при работе с react-router 4 и styled-components в React"
React + Redux — Замедление работы onChange в Input при вводе, когда значение берется из состояния