Значение по умолчанию для выбора реакции не определено при отправке

#reactjs #react-select

#reactjs #реагировать-выбрать

Вопрос:

Я использую react-select для одного меню выбора. defaultValue Кажется, что при редактировании формы отображается правильно, но при отправке формы возвращается значение, undefined если выбор оставлен без изменений. Если я нажму defaultValue , то при отправке он будет работать правильно. Есть ли что-то еще, чего prop мне не хватает для поддержки defaultValue сквозной отправки?

Код выглядит следующим образом:

 <Select
   closeMenuOnSelect={true}
   options={options()}
   defaultValue={defaultVal}
   className="basic-single"
   classNamePrefix="select"
/>
  

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

   const options = [
    { value: "chocolate", label: "Chocolate" },
    { value: "strawberry", label: "Strawberry" },
    { value: "vanilla", label: "Vanilla" }
  ];
  

И defaultVal возвращает единственное значение путем фильтрации options :

   let defaultVal = options().filter(
    (optionChoice) => optionChoice.label === props.choice
  );
  

Ответ №1:

Поскольку вы используете react-hook-form , вам необходимо использовать их Controller компонент для регистрации вашего выбора в форме. Ссылка здесь: Интеграция управляемых входных данных.

Следующее объявление компонента иллюстрирует перенос react-select компонента в react-hook-form компонент контроллера. Оно регистрируется с помощью react-hook-form с помощью control={control} , а затем отображает выбор через render prop компонента контроллера.

Вам также необходимо react-hook-form сообщить, когда выбор изменится, вызвав handleChange из select on change. handleChange() в свою очередь вызывает react-hook-form setValue() с измененным значением и shouldDirty: true помечает изменение.

 const handleChange = (change) => {
  setValue("controlledSelect", change, {
    shouldDirty: true
  });
};
  

Рабочая среда здесь:https://codesandbox.io/s/react-select-with-react-hook-form-im9hi

 import React from "react";
import { useForm, Controller } from "react-hook-form";
import Select from "react-select";

function ControlledSelect() {
  const { handleSubmit, control, setValue } = useForm();
  const [options, setOptions] = React.useState(initialOptions);

  const onSubmitData = (data) => {
    console.log(data);
  };

  const handleChange = (change) => {
    setValue("controlledSelect", change, {
      shouldDirty: true
    });
  };

  return (
    <div className="container">
      <form onSubmit={handleSubmit(onSubmitData)}>
        <Controller
          name="controlledSelect"
          control={control}
          defaultValue={options[1]}
          render={() => (
            <Select
              options={options}
              defaultValue={options[1]}
              onChange={handleChange}
            />
          )}
        />
        <button type="submit">Submit Select</button>
      </form>
    </div>
  );
}
  

Вот примерный фрагмент, показывающий рабочий выбор. Похоже, вы хотите объявить defaultValue как индекс в массиве: defaultValue={defaultVal[0]} . Это потребует создания вашего массива форматированных параметров перед визуализацией, а не передачи функции, что, вероятно, лучше в любом случае.

 <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://cdn.jsdelivr.net/npm/emotion@9.2.12/dist/emotion.umd.min.js"></script>

<script src="https://unpkg.com/prop-types@15.5.10/prop-types.min.js"></script>
<script src="https://unpkg.com/react-input-autosize@2.2.1/dist/react-input-autosize.min.js"></script>
<script src="https://unpkg.com/react-select@2.1.2/dist/react-select.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 {useRef} = React;
  
  const options = [
    { value: 'chocolate', label: 'Chocolate' },
    { value: 'strawberry', label: 'Strawberry' },
    { value: 'vanilla', label: 'Vanilla' }
  ]

function App() {
    const formRef = useRef();
    
    const submitForm = (e, ref) => {
      e.preventDefault();
      console.log(formRef.current.elements[1].value);

  }
  
    return (
      <form ref={formRef} onSubmit={submitForm}>
        <Select 
          name="select" 
          options={options} 
          defaultValue={options[1]} 
         />
        <input type="submit" value="Submit" />
      </form>
    )    
}

ReactDOM.render(<App />, document.getElementById('App'));
 </script>  

Комментарии:

1. options Находятся в функции, потому что они получены из массива, который необходимо сопоставить с value / label . Даже при этом defaultValue работает и отображается в console , но при отправке значение равно undefined . Я также использую react-hook-form , поэтому я не уверен, может ли это быть частью проблемы.

2. Да, react-hook-form что-то меняет. Я отредактировал свой ответ для объяснения и связал рабочий codesandbox.

3. спасибо, у меня была большая часть того, что вы включили помимо handleChange функции. Я все еще не могу заставить его работать, но я думаю, что это может быть связано с сохранением options как функции. Я собираюсь попытаться сохранить параметры, используя useState хук, как вы это сделали.

4. Мне не хватало одной вещи — я включал только defaultValue prop в <Select/> , но не в <Controller/> . Как только я это сделал, остальное сработало. Почему defaultValue необходимо дублировать в родительском и дочернем компонентах?

5. Это два отдельных компонента. На самом деле вы можете исключить его из любого из них, но у каждого есть свои последствия: если вы оставите его вне выбора, то начальное значение не будет установлено, но контроллер будет иметь (скрытое) начальное значение; если вы оставите контроллер, выбор будет отображать начальное значение, но пока вы не измените выбор (не запустите onChange), контроллер будет пустым. В конечном счете, именно контроллер отправляет значения, а Select предоставляет интерфейс. Рад, что у вас получилось!