Компонент змінює неконтрольований ввід тексту типу для керування помилкою в ReactJS


331

Попередження: Компонент змінює неконтрольований ввід тексту типу, яким потрібно керувати. Елементи введення не повинні переходити від неконтрольованих до контрольованих (або навпаки). Вирішіть між використанням керованого або неконтрольованого вхідного елемента протягом життя компонента. *

Слідує мій код:

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
конструктор (реквізит) {super (реквізит); this.state = {поля: {}, помилки: {}} this.onSubmit = this.onSubmit.bind (this); }
Рія Капурія

Відповіді:


650

Причина в тому, що ви визначили:

this.state = { fields: {} }

поля як порожній об'єкт, тому під час першого візуалізації this.state.fields.nameбуде undefined, а поле введення отримає своє значення у вигляді:

value={undefined}

Через це поле введення стане неконтрольованим.

Щойно ви вводите будь-яке значення вхідного сигналу, fieldsстан перетворюється на:

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

І в цей час поле введення перетворюється на керований компонент; ось чому ви отримуєте помилку:

Компонент змінює неконтрольований ввід тексту типу, який слід керувати.

Можливі рішення:

1- Визначте fieldsстан як:

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

2- Або визначте властивість значення, використовуючи оцінку короткого замикання так:

value={this.state.fields.name || ''}   // (undefined || '') = ''

5
є причина, що невизначена є "неконтрольованою", а остання "контрольованою" - що це означає?
Прашант Субраманійський

2
тому що ''це дійсне значення рядка. тож, коли ви переходите ''на "xyz", тип введення не змінює засоби, контрольовані на керовані. Але в разі undefinedз xyzтипом буде змінюватися від неконтрольованого до контрольованою.
Mayank Shukla

1
Дякую, що це працювало для мене:value={this.state.fields.name || ''}
Боб

1
Я не знав, що як тільки значення стає невизначеним, введення автоматично стає неконтрольованим, чудово. Вже виправте свою проблему
Адріан Серна

1
дивовижний! тому що я не бачив цього в офіційних документах, або я сліпий? посилання на джерело будь ласка :)
Dheeraj

34

Зміна valueдо defaultValueдозволить його.

Примітка :

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

Я використовував value={this.state.input ||""}в , inputщоб позбутися від цього попередження.


2
Дякую! Я зіткнувся з цією проблемою, і інші рішення не стосувалися мене, але це рішення допомогло.
PepperAddict

14

Всередині компонента поставте поле введення наступним чином.

<input className="class-name"
              type= "text"
              id="id-123"
              value={ this.state.value || "" }
              name="field-name"
              placeholder="Enter Name"
              />

13

ПРОСТО, спочатку потрібно встановити початковий стан

Якщо ви не встановите початковий стан, реагуйте на це як на неконтрольований компонент


10

На додаток до прийнятої відповіді, якщо ви використовуєте inputтип checkboxабо radio, я виявив, що мені потрібно також визначити нуль / невизначений перевірити checkedатрибут.

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

І якщо ви використовуєте TS (або Babel), ви можете використовувати нульове об'єднання замість логічного оператора АБО:

value={myStateValue ?? ''}
checked={someBoolean ?? false}

8

Встановіть спочатку поточний стан ...this.state

Це тому, що коли ви збираєтеся призначити новий стан, це може бути невизначено. тому він буде виправлений, встановивши також стан, який витягує поточний стан

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

Якщо в вашому стані є об’єкт, слід встановити стан таким чином, припустимо, що ви повинні встановити ім'я користувача всередині об’єкта користувача.

this.setState({user:{...this.state.user, ['username']: username}})

1
Наскільки я зрозумів, setState вже лише переосмислює поля, тому в першому випадку деструктурування присвоювати не повинно. У другому стані це може знадобитися, оскільки setState замінить оптовий об'єкт.
Kzqai

6
const [name, setName] = useState()

створює помилку, як тільки ви вводите текстове поле

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

вирішимо проблему на цьому рядковому прикладі.


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('');.

Порожній рядок у дужках - це різниця.
Крім того, якщо ви скинете форму після подання, як я, знову вам потрібно встановити порожній рядок, а не лише порожні дужки.

Це лише мій невеликий внесок у цю тему, можливо, хтось допоможе.


0

У моєму випадку це було майже все, що говорить вища відповідь Маянка Шукла. Єдина деталь полягала в тому, що в моєму стані повністю бракувало того майна, яке я визначав.

Наприклад, якщо у вас такий стан:

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

Попередження: Компонент змінює неконтрольований ввід тексту типу, яким потрібно керувати. Елементи введення не повинні переходити від неконтрольованих до контрольованих (або навпаки). Вирішіть між використанням керованого або неконтрольованого вхідного елемента протягом життя компонента.

Рішення: Перевірте, чи значення не визначено

React / Formik / Bootstrap / TypeScript

приклад:

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.