#reactjs
#reactjs
Вопрос:
Как отобразить параметры внутри тега выбора в ReactJS?
У меня есть данные json для страны и штата. Я хочу динамически отображать состояния в теге выбора с выбранной страной.
const onCountryChange = value => {
const country = value.split("_")[0];
const countryCode = value.split("_")[1];
const countryId = value.split("_")[2];
setCountry(country);
setCountryCode(countryCode);
setCountryId(countryId)
};
Выберите тег для страны
<select value={country} onChange={e => onCountryChange(e.target.value)}>
<option value="" disabled>Select Country</option>
{
COUNTRIES.map((country, index) => {
return (
<option
key={index}
value={country.name "_ " country.phoneCode "_" country.id}
>
{country.name}
</option>
);
})
}
</select>
Выберите тег для состояния
<select value={state} onChange={e => onStateChange(e.target.value)} >
<option value="" disabled>Select State/Province</option>
{
STATES.filter(states => (states.country_id === countryId)).map((state, index) => {
console.log(state.name)
return (
<option
key={index}
value={state.name "_ " state.id}
>
{state.name}
</option>
);
})
}
</select>
Выпадающий список для страны отображается правильно. Когда я выбираю страну, соответствующие состояния не отображаются в теге выбора, где состояния as отображаются в консоли.
Комментарии:
1. Я бы предположил, что, поскольку вы используете
index
в качестве ключевого, React избегает перезаписи там, где это возможно. Скорее используйтеkey={state.id}
. Согласно документам: мы не рекомендуем использовать индексы для ключей, если порядок элементов может измениться. Это может негативно повлиять на производительность и вызвать проблемы с состоянием компонента. Ознакомьтесь со статьей Робина Покорни для подробного объяснения негативных последствий использования индекса в качестве ключа. Если вы решите не назначать явный ключ элементам списка, то React по умолчанию будет использовать индексы в качестве ключей. Списки и ключи2. Я действительно сменил ключ на state.id но безуспешно
Ответ №1:
Не видя больше вашего кода, я не могу точно ответить на ваш вопрос, но я предоставил базовый рабочий фрагмент, который использует простой многоразовый Select
компонент и хранит идентификаторы выбранной страны и штата с использованием useState
.
Кроме того, в вашем коде есть некоторые существенные недостатки, которые, если вы их устраните, сделают все более читаемым и могут помочь избежать или легче найти ошибки в поведении или выводе.
Во-первых, у вас много дублирования при написании двух отдельных select
элементов, которые вы еще больше усложнили, вернув их изнутри. Сейчас самое время абстрагироваться от отдельного компонента.
function Select({ options, value, title, handleSelectChange }) {
return (
<select name="title" value={value ? value : ''} onChange={handleSelectChange} >
<option value="" disabled selected hidden>{title}</option>
{options.map(option =>
<option key={option.id} value={option.id} >
{option.name}
</option>
)}
</select>
)
}
Далее вы объявляете анонимную функцию в onChange
для вызова именованной функции и только передаете event
. Именованные функции в React могут вызываться по прямой ссылке, и им будет передано событие по сути, чтобы вы могли упростить свой код таким образом:
const onCountryChange = (event) => {
console.log(event.target.value);
...
}
<select ... onChange={onCountryChange}>
Внутри onCountryChange
снова много дублирования (и три вызова split
одной и той же строки). Вы можете использовать назначение деструктурирования, чтобы упростить это
const onCountryChange = (e) => {
const [country, countryCode, countryId] = e.target.value.split("_");
}
Это небольшие указатели, но изучение основ и кодирование как можно более чисто помогут избежать путаницы.
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<div id="App"></div>
<script type="text/babel">
const { useState} = React;
const countries = [
{ id: 'AD', name: 'Andorra' },
{ id: 'AE', name: 'United Arab Emirates' },
{ id: 'AF', name: 'Afghanistan' },
{ id: 'AG', name: 'Antigua and Barbuda' },
{ id: 'AI', name: 'Anguilla' },
]
const states = [
{ id: 'ad1', name: 'AD: State 1', countryId: 'AD' },
{ id: 'ad2', name: 'AD: State 2', countryId: 'AD' },
{ id: 'ad3', name: 'AD: State 3', countryId: 'AD' },
{ id: 'st1', name: 'AI: State 4', countryId: 'AI' },
{ id: 'st2', name: 'AI: State 5', countryId: 'AI' },
{ id: 'st3', name: 'AI: State 6', countryId: 'AI' },
{ id: 'ag1', name: 'AG: State 7', countryId: 'AG' },
{ id: 'ag2', name: 'AG: State 8', countryId: 'AG' },
{ id: 'ag3', name: 'AG: State 9', countryId: 'AG' },
{ id: 'af1', name: 'AF: State 10', countryId: 'AF' },
{ id: 'af2', name: 'AF: State 11', countryId: 'AF' },
{ id: 'af3', name: 'AF: State 12', countryId: 'AF' },
{ id: 'ae1', name: 'AE: State 13', countryId: 'AE' },
{ id: 'ae2', name: 'AE: State 14', countryId: 'AE' },
{ id: 'ae3', name: 'AE: State 35', countryId: 'AE' }
]
function Select({ options, value, title, handleSelectChange }) {
return (
<select name="title" value={value ? value : ''} onChange={handleSelectChange} >
<option value="" disabled selected hidden>{title}</option>
{options.map(option =>
<option key={option.id} value={option.id} >
{option.name}
</option>
)}
</select>
)
}
function App() {
const [selectedCountryId, setSelectedCountryId] = useState(null);
const [selectedStateId, setSelectedStateId] = useState(null);
const handleCountryChange = (e) => {
setSelectedStateId(null);
setSelectedCountryId(e.target.value);
}
const handleStateChange = (e) => {
setSelectedStateId(e.target.value);
}
return (
<div>
<div className="select-container">
<Select
options={countries}
value={selectedCountryId}
title='Select Country'
handleSelectChange={handleCountryChange}
/>
<Select
options={states.filter(state =>
state.countryId === selectedCountryId)}
value={selectedStateId}
title='Select State/Province'
handleSelectChange={handleStateChange}
/>
</div>
<div class='output'>
<p>Selected Country Id: {selectedCountryId}</p>
<p>Selected State Id: {selectedStateId}</p>
</div>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('App'));
</script>
Комментарии:
1. Спасибо, что указали на дублирование кода. Я следовал предложенному подходу. Я создал отдельный компонент для
select
элемента и использовал его в родительском компоненте. Страны отображаются, но состояния не отображаются. Однако я мог видеть названия штатов в консоли. PS: мой код выглядит точно так же, как ваш фрагмент.2. Я рад, что это помогло. Не видя вашего кода, я не могу сказать, почему он не работает. Приведенный выше фрагмент работает, возможно, вы можете попробовать сравнить шаг за шагом (даже если он не идентичен), чтобы найти, где вы отклоняетесь?
3. Я забыл упомянуть ранее. Состояния отображаются, когда я удаляю функциональность фильтра. Но при этом все состояния будут доступны в выпадающем списке.
4. ну, вот где вы ошибаетесь, тогда убедитесь, что ваша функция фильтра работает вне цикла и что она правильно ссылается на
countryID
сохраненное состояние.5. Я дважды проверил это, все правильно. Я не знаю, почему состояния не отображаются. Я мог видеть, как состояния меняются в консоли с изменением страны.