Eine Komponente ändert eine unkontrollierte Eingabe vom Typ Text, um Fehler in ReactJS zu steuern


329

Warnung: Eine Komponente ändert eine unkontrollierte Eingabe des zu steuernden Texttyps. Eingangselemente sollten nicht von unkontrolliert zu kontrolliert (oder umgekehrt) wechseln. Entscheiden Sie sich für die Lebensdauer der Komponente zwischen der Verwendung eines gesteuerten oder unkontrollierten Eingabeelements. *

Folgendes ist mein 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>
  )
}

1
Was ist der Anfangswert von fieldsin state?
Mayank Shukla

2
Konstruktor (Requisiten) {Super (Requisiten); this.state = {Felder: {}, Fehler: {}} this.onSubmit = this.onSubmit.bind (this); }
Riya Kapuria

Antworten:


645

Der Grund ist in dem von Ihnen definierten Zustand:

this.state = { fields: {} }

Felder als leeres Objekt, so dass während des ersten Rendering this.state.fields.namewerden undefined, und das Eingabefeld seinen Wert erhalten als:

value={undefined}

Dadurch wird das Eingabefeld unkontrolliert.

Sobald Sie einen Wert in die Eingabe eingegeben haben, wird der fieldsStatus in geändert in:

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

Zu diesem Zeitpunkt wird das Eingabefeld in eine gesteuerte Komponente umgewandelt. Deshalb erhalten Sie den Fehler:

Eine Komponente ändert eine unkontrollierte Eingabe des zu steuernden Texttyps.

Mögliche Lösungen:

1- Definieren Sie den fieldsStatus in als:

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

2- Oder definieren Sie die Werteigenschaft mithilfe der folgenden Kurzschlussauswertung :

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

3
Gibt es einen Grund, warum undefiniert "unkontrolliert" ist, während letzterer "kontrolliert" ist - was bedeuten diese?
Prashanth Subramanian

@PrashanthSubramanian Vielleicht könnte dies helfen, es besser zu verstehen. reactjs.org/docs/forms.html#controlled-components
rotimi-best

Ich habe während des Änderungsereignisses keine undefinierten in meinem Zustand
Alexey Sh.

2
weil ''ist ein gültiger Zeichenfolgenwert. Wenn Sie also ''zu 'xyz' wechseln, ändert der Eingabetyp nicht die Mittel, die gesteuert zu gesteuert werden. Im Falle von undefinedto wechselt der xyzTyp jedoch von unkontrolliert zu kontrolliert.
Mayank Shukla

1
tolle! weil ich das nicht in den offiziellen Dokumenten erwähnt habe, oder bin ich blind? Link zur Quelle bitte :)
Dheeraj

34

Durch Ändern valuein defaultValuewird das Problem behoben.

Hinweis :

defaultValueist nur für die anfängliche Belastung. Wenn Sie das initialisieren möchten, inputsollten Sie verwenden defaultValue, aber wenn Sie stateden Wert ändern möchten, müssen Sie verwenden value. Lesen Sie dies für mehr.

Früher habe ich value={this.state.input ||""}in inputdieser Warnung loszuwerden.


2
Vielen Dank! Ich bin auf dieses Problem gestoßen und die anderen Lösungen haben sich nicht auf mich ausgewirkt, aber diese Lösung hat geholfen.
PepperAddict

14

Fügen Sie innerhalb der Komponente das Eingabefeld folgendermaßen ein.

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

13

EINFACH müssen Sie zuerst den Anfangszustand einstellen

Wenn Sie den Anfangszustand nicht festlegen, wird durch Reagieren eine unkontrollierte Komponente behandelt


10

Zusätzlich zur akzeptierten Antwort muss das Attribut auch null / undefiniert überprüft werden , wenn Sie einen inputTyp checkboxoder verwenden .radiochecked

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

Und wenn Sie TS (oder Babel) verwenden, können Sie anstelle des logischen ODER-Operators nullish coalescing verwenden:

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

8

Stellen Sie zuerst den aktuellen Status ein ...this.state

Dies liegt daran, dass ein neuer Status möglicherweise nicht definiert ist, wenn Sie ihn zuweisen. Daher wird dies behoben, indem der Status so eingestellt wird, dass auch der aktuelle Status extrahiert wird

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

Wenn sich in Ihrem Status ein Objekt befindet, sollten Sie den Status wie folgt festlegen. Angenommen, Sie müssen den Benutzernamen im Benutzerobjekt festlegen.

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

1
Soweit ich weiß, überschreibt setState bereits nur Felder, sodass es im ersten Fall unnötig sein sollte, die Zuweisung zu zerstören. Im zweiten Zustand kann dies erforderlich sein, da setState einen Unterobjekt-Großhandel ersetzt.
Kzqai

6
const [name, setName] = useState()

generiert einen Fehler, sobald Sie das Textfeld eingeben

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

behebt das Problem in diesem Zeichenfolgenbeispiel.


2

Wenn Sie mehrere Eingaben in ein Feld verwenden, gehen Sie wie folgt vor: Zum Beispiel:

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

Suchen Sie Ihr Problem unter:

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

1

Vergessen Sie bei der Verwendung von React Hooks auch nicht, den Anfangswert festzulegen.
Ich benutzte <input type='datetime-local' value={eventStart} />und Initiale eventStartwar wie

const [eventStart, setEventStart] = useState();
stattdessen
const [eventStart, setEventStart] = useState('');.

Die leere Zeichenfolge in Klammern ist ein Unterschied.
Wenn Sie das Formular nach dem Senden zurücksetzen, wie ich es tue, müssen Sie es erneut auf eine leere Zeichenfolge setzen, nicht nur auf leere Klammern.

Dies ist nur mein kleiner Beitrag zu diesem Thema, vielleicht hilft es jemandem.


0

In meinem Fall war es so ziemlich das, was Mayank Shuklas Top-Antwort sagt. Das einzige Detail war, dass meinem Staat die von mir definierte Eigenschaft völlig fehlte.

Wenn Sie beispielsweise diesen Status haben:

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

Wenn Sie Ihren Code erweitern, möchten Sie möglicherweise eine neue Requisite hinzufügen, sodass Sie an einer anderen Stelle in Ihrem Code möglicherweise eine neue Eigenschaft erstellen, cderen Wert nicht nur für den Status der Komponente undefiniert ist, sondern die Eigenschaft selbst nicht definiert ist.

Um dies zu lösen, fügen cSie einfach Ihren Status hinzu und geben Sie ihm einen geeigneten Anfangswert.

z.B,

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

Ich hoffe, ich konnte meinen Randfall erklären.


0

Ich erhalte die gleiche Warnung: Eine Komponente ändert eine unkontrollierte Eingabe vom Typ versteckt, um gesteuert zu werden. Ich kann mein Problem nicht beheben. Irgendwelche Ideen warum?

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>

Ich habe es versucht ({ valueName, valueName: {geschlecht=""}, onChangeAllg,})undvalue={valueName.geschlecht || ""}


ich habe es gefunden. Ein defaultValue={""}Inneres des TextFields fehlte
Dr. Malte Westerloh

0

Warnung: Eine Komponente ändert eine unkontrollierte Eingabe des zu steuernden Texttyps. Eingangselemente sollten nicht von unkontrolliert zu kontrolliert (oder umgekehrt) wechseln. Entscheiden Sie sich für die Lebensdauer der Komponente zwischen der Verwendung eines gesteuerten oder unkontrollierten Eingabeelements.

Lösung: Überprüfen Sie, ob der Wert nicht undefiniert ist

Reagieren Sie / Formik / Bootstrap / TypeScript

Beispiel:

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.