Компонент изменяет неконтролируемый ввод текста типа, чтобы контролировать ошибку в ReactJS

332

Предупреждение. Компонент изменяет неконтролируемый ввод текста типа для управления. Элементы ввода не должны переключаться с неконтролируемого на управляемый (или наоборот). Выберите между использованием контролируемого или неконтролируемого входного элемента в течение срока службы компонента. *

Ниже приведен мой код:

constructor(props) {
  super(props);
  this.state = {
    fields: {},
    errors: {}
  }
  this.onSubmit = this.onSubmit.bind(this);
}

....

onChange(field, e){
  let fields = this.state.fields;
  fields[field] = e.target.value;
  this.setState({fields});
}

....

render() {
  return(
    <div className="form-group">
      <input
        value={this.state.fields["name"]}
        onChange={this.onChange.bind(this, "name")}
        className="form-control"
        type="text"
        refs="name"
        placeholder="Name *"
      />
      <span style={{color: "red"}}>{this.state.errors["name"]}</span>
    </div>
  )
}
Рия Капурия
источник
2
какова начальная стоимость fieldsв состоянии?
Mayank Shukla
2
конструктор (реквизит) {супер (реквизит); this.state = {fields: {}, ошибки: {}} this.onSubmit = this.onSubmit.bind (this); }
Рия Капурия
2
Возможный дубликат React - изменение неконтролируемого ввода
Майкл

Ответы:

652

Причина в том, что вы определили:

this.state = { fields: {} }

поля как пустой объект, поэтому во время первого рендеринга this.state.fields.nameбудет undefined, а поле ввода получит свое значение в виде:

value={undefined}

Из-за этого поле ввода станет неуправляемым.

Как только вы введете любое значение на входе, fieldsсостояние будет изменено на:

this.state = { fields: {name: 'xyz'} }

И в это время поле ввода преобразуется в управляемый компонент; вот почему вы получаете ошибку:

Компонент изменяет неконтролируемый ввод текста типа для управления.

Возможные решения:

1- Определите fieldsв состоянии как:

this.state = { fields: {name: ''} }

2- Или определите свойство value с помощью оценки короткого замыкания следующим образом:

value={this.state.fields.name || ''}   // (undefined || '') = ''
Маянк Шукла
источник
5
есть ли причина, по которой неопределенная является «неконтролируемой», а последняя «контролируемой» - что это значит?
Прашант Субраманян
2
потому что ''является допустимым строковым значением. поэтому, когда вы изменяете ''на 'xyz', тип ввода не меняется, значит контролируемый на контролируемый. Но в случае undefinedс xyzтипом изменится с неконтролируемого на контролируемый.
Mayank Shukla
1
Спасибо, это сработало для меня:value={this.state.fields.name || ''}
Боб
1
Я не знал, что как только значение становится неопределенным, вход автоматически становится неуправляемым, Отлично. Уже решаю мою проблему
Адриан Серна
1
удивительный! потому что я не видел этого в официальных документах, или я слепой? ссылку на источник, пожалуйста :)
Dheeraj
36

Изменение valueк defaultValueразрешит его.

Примечание :

defaultValueтолько для начальной загрузки. Если вы хотите инициализировать inputто, вы должны использовать defaultValue, но если вы хотите использовать, stateчтобы изменить значение, то вам нужно использовать value. Прочитайте это для большего.

Я использовал value={this.state.input ||""}в , inputчтобы избавиться от этого предупреждения.

MoFoLuWaSo
источник
2
Спасибо! Я столкнулся с этой проблемой, и другие решения не относились ко мне, но это решение помогло.
PepperAddict
14

ПРОСТО, сначала нужно установить начальное состояние

Если вы не установили начальное состояние, реакция будет рассматриваться как неконтролируемый компонент.

Вайбхав Бахчав
источник
14

Внутри компонента поместите поле ввода следующим образом.

<input className="class-name"
              type= "text"
              id="id-123"
              value={ this.state.value || "" }
              name="field-name"
              placeholder="Enter Name"
              />
Tabish
источник
10

В дополнение к принятому ответу, если вы используете inputтип checkboxили radio, я обнаружил, что мне также необходимо проверить checkedатрибут на null / undefined .

<input
  id={myId}
  name={myName}
  type="checkbox" // or "radio"
  value={myStateValue || ''}
  checked={someBoolean ? someBoolean : false}
  />

И если вы используете TS (или Babel), вы можете использовать нулевое слияние вместо логического оператора OR:

value={myStateValue ?? ''}
checked={someBoolean ?? false}
Линден Ной
источник
8

Сначала установите текущее состояние ...this.state

Это потому, что когда вы собираетесь назначить новое состояние, оно может быть неопределенным. так что это будет исправлено путем установки состояния извлечения текущего состояния также

this.setState({...this.state, field})

Если в вашем состоянии есть объект, вы должны установить состояние следующим образом, предположим, что вы должны установить имя пользователя внутри объекта пользователя.

this.setState({user:{...this.state.user, ['username']: username}})
NuOne
источник
1
Насколько я понимаю, setState уже переопределяет только поля, поэтому в первом случае не нужно деструктурировать присвоение. Во втором состоянии это может быть необходимо, так как setState заменит оптовый объект подобъекта.
Kzqai
6
const [name, setName] = useState()

выдает ошибку, как только вы вводите текстовое поле

const [name, setName] = useState('') // <-- by putting in quotes 

исправит проблему в этом примере строки.

Nelles
источник
2

Если вы используете множественный ввод в поле, выполните следующие действия: Например:

class AddUser extends React.Component {
   constructor(props){
     super(props);

     this.state = {
       fields: { UserName: '', Password: '' }
     };
   }

   onChangeField = event => {
    let name = event.target.name;
    let value = event.target.value;
    this.setState(prevState => {
        prevState.fields[name] =  value;
        return {
           fields: prevState.fields
        };
    });
  };

  render() { 
     const { UserName, Password } = this.state.fields;
     return (
         <form>
             <div>
                 <label htmlFor="UserName">UserName</label>
                 <input type="text" 
                        id='UserName' 
                        name='UserName'
                        value={UserName}
                        onChange={this.onChangeField}/>
              </div>
              <div>
                  <label htmlFor="Password">Password</label>
                  <input type="password" 
                         id='Password' 
                         name='Password'
                         value={Password}
                         onChange={this.onChangeField}/>
              </div>
         </form>
     ); 
  }
}

Поиск вашей проблемы на:

onChangeField = event => {
    let name = event.target.name;
    let value = event.target.value;
    this.setState(prevState => {
        prevState.fields[name] =  value;
        return {
            fields: prevState.fields
        };
    });
};
Хамидреза Рафиэй
источник
1

Использование React Hooks также не забудьте установить начальное значение.
Я использовал, <input type='datetime-local' value={eventStart} />и начальный eventStartбыл как

const [eventStart, setEventStart] = useState();
вместо
const [eventStart, setEventStart] = useState('');.

Пустая строка в скобках - это разница.
Кроме того, если вы сбрасываете форму после отправки, как я, снова вам нужно установить ее на пустую строку, а не только на пустые скобки.

Это всего лишь мой небольшой вклад в эту тему, возможно, это кому-нибудь поможет.

Zrna
источник
0

В моем случае это было в значительной степени то, что говорит главный ответ Mayank Shukla. Единственная деталь заключалась в том, что в моем штате отсутствовала собственность, которую я определял.

Например, если у вас есть это состояние:

state = {
    "a" : "A",
    "b" : "B",
}

Если вы расширяете свой код, возможно, вы захотите добавить новую опору, чтобы в другом месте кода вы могли создать новое свойство c, значение которого не только не определено в состоянии компонента, но и само свойство не определено.

Чтобы решить эту проблему, просто добавьте c в ваше состояние и задайте правильное начальное значение.

например,

state = {
    "a" : "A",
    "b" : "B",
    "c" : "C", // added and initialized property!
}

Надеюсь, мне удалось объяснить мой крайний случай.

Даниэль Сегура
источник
0

Я получаю то же предупреждение: компонент изменяет неконтролируемый ввод скрытого типа для управления. Я не могу решить мою проблему. Есть идеи почему?

export default ({  valueName, onChangeAllg,}) => {

          <TextField
            id={"name"}
            select
            label={"name"}
            value={valueName.geschlecht || ""}
            name={"name"}
            onChange={onChangeAllg}

          >
            {nameList.map((option) => (
              <MenuItem key={option.value} value={option.value}>
                {option.label}
              </MenuItem>
            ))}
          </TextField>

я попробовал ({ valueName, valueName: {geschlecht=""}, onChangeAllg,})иvalue={valueName.geschlecht || ""}

Доктор Малте Вестерло
источник
я нашел это. defaultValue={""}Внутри TextField не хватает
доктор Malte Westerloh
0

Предупреждение. Компонент изменяет неконтролируемый ввод текста типа для управления. Элементы ввода не должны переключаться с неконтролируемого на управляемый (или наоборот). Выберите между использованием контролируемого или неконтролируемого элемента ввода в течение срока службы компонента.

Решение: проверьте, не является ли значение неопределенным

Реагировать / Formik / Bootstrap / TypeScript

пример :

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
user3706761
источник