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>
  )
}
Riya Kapuria
la source
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
2
Duplicata possible de React - modification d'une entrée non contrôlée
Michael Freidgeim

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 || '') = ''
Mayank Shukla
la source
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.

MoFoLuWaSo
la source
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é

Vaibhav Bacchav
la source
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"
              />
Tabish
la source
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}
Lynden Noye
la source
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}})
NuOne
la source
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.

Nelles
la source
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
        };
    });
};
Hamidreza Rafiei
la source
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.

Zrna
la source
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.

Daniel Segura
la source
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 || ""}

Dr. Malte Westerloh
la source
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
}
user3706761
la source