Un composant modifie une entrée non contrôlée de type texte à contrôler, erreur dans ReactJS


332

Avertissement: un composant modifie une entrée non contrôlée de type texte à contrôler. Les éléments d'entrée ne doivent pas passer de non contrôlés à contrôlés (ou vice versa). Décidez entre l'utilisation d'un élément d'entrée contrôlé ou non contrôlé pendant la durée de vie du composant. *

Voici mon code:

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
quelle est la valeur initiale de fieldsin state?
Mayank Shukla

2
constructeur (accessoires) {super (accessoires); this.state = {champs: {}, erreurs: {}} this.onSubmit = this.onSubmit.bind (this); }
Riya Kapuria

Réponses:


651

La raison en est, dans l'état que vous avez défini:

this.state = { fields: {} }

champs comme un objet vide, donc lors du premier rendu this.state.fields.namesera undefined, et le champ d'entrée obtiendra sa valeur comme:

value={undefined}

Pour cette raison, le champ de saisie deviendra incontrôlé.

Une fois que vous avez entré une valeur en entrée, l' fieldsétat devient:

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

Et à ce moment, le champ d'entrée est converti en un composant contrôlé; c'est pourquoi vous obtenez l'erreur:

Un composant modifie une entrée non contrôlée de type texte à contrôler.

Solutions possibles:

1- Définissez l' fieldsétat in comme:

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

2- Ou définissez la propriété value en utilisant une évaluation de court-circuit comme ceci:

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

5
y a-t-il une raison indéfinie qui est "incontrôlée" alors que cette dernière est "contrôlée" - qu'est-ce que cela signifie?
Prashanth Subramanian

2
car ''est une valeur de chaîne valide. Ainsi, lorsque vous passez ''à «xyz», le type d'entrée ne change pas les moyens contrôlés en contrôlés. Mais dans le cas de undefinedla xyzcatégorie passera de incontrôlée contrôlée.
Mayank Shukla

1
Merci, cela a fonctionné pour moi:value={this.state.fields.name || ''}
Bob

1
Je ne savais pas qu'une fois la valeur indéfinie, l'entrée devenait automatiquement incontrôlée, super. Je résout déjà mon problème
Adrian Serna

1
incroyable! parce que je n'ai pas vu cela mentionné dans les documents officiels, ou suis-je aveugle? lien vers la source s'il vous plaît :)
Dheeraj

35

Changer valuepour defaultValuele résoudre.

Remarque :

defaultValueest uniquement pour la charge initiale. Si vous souhaitez initialiser le, inputvous devez utiliser defaultValue, mais si vous souhaitez utiliser statepour modifier la valeur, vous devez utiliser value. Lisez ceci pour en savoir plus.

Je value={this.state.input ||""}en inputpour se débarrasser de cet avertissement.


2
Je vous remercie! J'ai rencontré ce problème et les autres solutions ne s'appliquent pas à moi, mais cette solution a aidé.
PepperAddict

14

SIMPLEMENT, vous devez d'abord définir l'état initial

Si vous ne définissez pas l'état initial, réagir le traitera comme un composant non contrôlé


14

À l'intérieur du composant, placez la zone de saisie de la manière suivante.

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

10

En plus de la réponse acceptée, si vous utilisez un inputtype checkboxou radio, j'ai trouvé que je dois également vérifier l' checkedattribut null / undefined .

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

Et si vous utilisez TS (ou Babel), vous pouvez utiliser la fusion nulle au lieu de l'opérateur logique OU:

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

8

Définir l'état actuel en premier ...this.state

C'est parce que lorsque vous allez attribuer un nouvel état, il peut ne pas être défini. il sera donc fixé en définissant l'état d'extraction de l'état actuel également

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

S'il y a un objet dans votre état, vous devez définir l'état comme suit, supposons que vous devez définir le nom d'utilisateur dans l'objet utilisateur.

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

1
Pour autant que je le comprenne, setState ne remplace déjà que les champs, donc dans le premier cas il ne devrait pas être nécessaire de détruire assigner. Dans le second état, cela peut être nécessaire car setState remplacera un sous-objet en gros.
Kzqai

6
const [name, setName] = useState()

génère une erreur dès que vous tapez dans le champ de texte

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

va résoudre le problème sur cet exemple de chaîne.


2

Si vous utilisez plusieurs entrées dans le champ, suivez: Par exemple:

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>
     ); 
  }
}

Recherchez votre problème sur:

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

1

L'utilisation de React Hooks n'oublie pas non plus de définir la valeur initiale.
J'utilisais <input type='datetime-local' value={eventStart} />et l'initiale eventStartétait comme

const [eventStart, setEventStart] = useState();
à la place
const [eventStart, setEventStart] = useState('');.

La chaîne vide entre parenthèses est la différence.
De plus, si vous réinitialisez le formulaire après l'envoi comme je le fais, vous devez à nouveau le définir sur une chaîne vide, pas seulement sur des parenthèses vides.

Ceci est juste ma petite contribution à ce sujet, peut-être que cela aidera quelqu'un.


0

Dans mon cas, c'était à peu près ce que dit la meilleure réponse de Mayank Shukla. Le seul détail était que mon état manquait complètement de la propriété que je définissais.

Par exemple, si vous avez cet état:

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

Si vous développez votre code, vous voudrez peut-être ajouter un nouvel accessoire afin que, ailleurs dans votre code, vous puissiez créer une nouvelle propriété cdont la valeur n'est pas seulement indéfinie sur l'état du composant, mais la propriété elle - même n'est pas définie.

Pour résoudre ce problème, assurez-vous d'ajouter cà votre état et de lui donner une valeur initiale appropriée.

par exemple,

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

J'espère que j'ai pu expliquer mon cas de bord.


0

Je reçois le même avertissement: un composant modifie une entrée non contrôlée de type caché à contrôler. Je ne peux pas résoudre mon problème. Des idées pourquoi?

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>

j'ai essayé ({ valueName, valueName: {geschlecht=""}, onChangeAllg,})etvalue={valueName.geschlecht || ""}


je l'ai trouvé. Il defaultValue={""}manquait un intérieur du TextField
Dr. Malte Westerloh

0

Avertissement: un composant modifie une entrée non contrôlée de type texte à contrôler. Les éléments d'entrée ne doivent pas passer de non contrôlés à contrôlés (ou vice versa). Décidez entre l'utilisation d'un élément d'entrée contrôlé ou non contrôlé pendant la durée de vie du composant.

Solution: vérifiez si la valeur n'est pas indéfinie

React / Formik / Bootstrap / TypeScript

exemple :

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.