Динамический выпадающий список для страны и штата в ReactJS

#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. Я дважды проверил это, все правильно. Я не знаю, почему состояния не отображаются. Я мог видеть, как состояния меняются в консоли с изменением страны.