Реагировать - изменение неконтролируемого входа

172

У меня есть простой компонент реакции с формой, которая, как я полагаю, имеет один управляемый вход:

import React from 'react';

export default class MyForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {}
    }

    render() {
        return (
            <form className="add-support-staff-form">
                <input name="name" type="text" value={this.state.name} onChange={this.onFieldChange('name').bind(this)}/>
            </form>
        )
    }

    onFieldChange(fieldName) {
        return function (event) {
            this.setState({[fieldName]: event.target.value});
        }
    }
}

export default MyForm;

Когда я запускаю свое приложение, я получаю следующее предупреждение:

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

Я считаю, что мой вход контролируется, поскольку он имеет значение. Мне интересно, что я делаю неправильно?

Я использую React 15.1.0

Теги:
spread-operator

10 ответов

243
Лучший ответ

Я считаю, что мой вход управляется, поскольку он имеет значение.

Для управляемого входа его значение должно соответствовать значению переменной состояния.

Это условие изначально не встречается в вашем примере, потому что this.state.name изначально не задано. Следовательно, вход изначально неконтролируемый. Как только обработчик onChange запускается в первый раз, устанавливается this.state.name. В этот момент указанное условие выполняется, и ввод считается контролируемым. Этот переход от неконтролируемого к контролируемому приводит к ошибке, наблюдаемой выше.

Инициализируя this.state.name в конструкторе:

например.

this.state = { name: '' };

вход будет управляться с самого начала, фиксируя проблему. Подробнее см. "Реагировать контролируемые компоненты" .

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

  • 0
    Трудно прочитать ответ и следовать этой идее много раз, но этот ответ является идеальным способом рассказать историю и заставить зрителя понять одновременно. Ответь богу уровня!
  • 1
    Что делать, если у вас есть динамические поля в цикле? например, вы установили имя поля равным name={'question_groups.${questionItem.id}'} ?
Показать ещё 3 комментария
81

Когда вы сначала визуализируете свой компонент, this.state.name не установлен, поэтому он оценивается как undefined, и вы заканчиваете передачу value={undefined} на input.

Когда ReactDOM проверяет, контролируется ли поле, проверяет, есть ли value != null (обратите внимание, что это !=, а не !==), и поскольку undefined == null в JavaScript, он решает, что он неконтролируемый.

Итак, когда вызывается onFieldChange(), this.state.name устанавливается в строковое значение, ваш вход переходит из неконтролируемого управления.

Если вы выполняете this.state = {name: ''} в своем конструкторе, потому что '' != null, ваш ввод будет иметь значение все время, и это сообщение исчезнет.

  • 4
    Для чего бы это ни стоило, то же самое может случиться с this.props.<whatever> , что было проблемой с моей стороны. Спасибо, Адам!
  • 0
    Ага! Это также может произойти, если вы передадите вычисляемую переменную, которую вы определили в render() , или выражение в самом теге - все, что оценивается как undefined . Рад, что смог помочь!
Показать ещё 6 комментариев
23

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

 <input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
  • 1
    <input name = "name" type = "text" defaultValue = "" onChange = {this.onFieldChange ('name'). bind (this)} /> Я думаю, это также будет работать
  • 0
    Большое спасибо, это было именно то, что я искал. Есть ли какие-либо недостатки или потенциальные проблемы при использовании этого шаблона, которые я должен иметь в виду?
Показать ещё 1 комментарий
4

Я знаю, что другие уже ответили на это. Но один из очень важных факторов здесь может помочь другим людям, испытывающим подобную проблему:

В поле ввода необходимо добавить обработчик onChange (например, textField, флажок, радио и т.д.). И всегда обрабатывайте активность с помощью обработчика onChange, например:

<input ... onChange={ this.myChangeHandler} ... />

и когда вы работаете с флажком, вам может потребоваться обработать его состояние checked с помощью !!, например:

<input type="checkbox" checked={!!this.state.someValue} onChange={.....} >

Ссылка: https://github.com/facebook/react/issues/6779#issuecomment-326314716

2

Когда вы используете onChange={this.onFieldChange('name').bind(this)} во входных данных, вы должны объявить пустую строку вашего состояния в качестве значения поля свойства.

неверный путь:

this.state ={
       fields: {},
       errors: {},
       disabled : false
    }

правильный путь:

this.state ={
       fields: {
         name:'',
         email: '',
         message: ''
       },
       errors: {},
       disabled : false
    }
1

Один потенциальный недостаток при установке значения поля "" (пустая строка) в конструкторе - это если поле является необязательным и оставлено неотредактированным. Если вы не сделаете некоторый массаж перед отправкой формы, поле будет сохранено в вашем хранилище данных в виде пустой строки вместо NULL.

Эта альтернатива позволит избежать пустых строк:

constructor(props) {
    super(props);
    this.state = {
        name: null
    }
}

... 

<input name="name" type="text" value={this.state.name || ''}/>
1

Установите значение для свойства name в начальном состоянии.

this.state={ name:''};
1

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

<input type="text" placeholder={object.property} value={object.property ? object.property : ""}>
0

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

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

Лучший способ избежать этого - объявить некоторое значение для ввода в конструкторе компонента. Так что элемент input имеет значение с самого начала приложения.

0

В моем случае я упустил что-то действительно тривиальное.

<input value={state.myObject.inputValue}/>

Мое состояние было следующим, когда я получал предупреждение:

state = {
   myObject: undefined
}

Чередуя мое состояние со ссылкой на ввод моей стоимости, моя проблема была решена:

state = {
   myObject: {
      inputValue: ''
   }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню