Komponent zmienia niekontrolowane wprowadzanie tekstu tekstowego w celu kontrolowania błędu w ReactJS

331

Ostrzeżenie: składnik zmienia niekontrolowane wprowadzanie tekstu tekstowego, który ma być kontrolowany. Elementy wejściowe nie powinny przełączać się z niekontrolowanego na kontrolowane (lub odwrotnie). Wybierz między użyciem kontrolowanego lub niekontrolowanego elementu wejściowego przez cały okres użytkowania komponentu. *

Oto mój kod:

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
źródło
2
Jaka jest początkowa wartość fieldsw stanie?
Mayank Shukla
2
konstruktor (rekwizyty) {super (rekwizyty); this.state = {pola: {}, błędy: {}} this.onSubmit = this.onSubmit.bind (this); }
Riya Kapuria
2
Możliwy duplikat React - zmiana niekontrolowanego wejścia
Michael Freidgeim

Odpowiedzi:

650

Powodem jest, w stanie, który zdefiniowałeś:

this.state = { fields: {} }

pola jako pusty obiekt, więc podczas pierwszego renderowania this.state.fields.namebędzie undefined, a pole wejściowe otrzyma swoją wartość jako:

value={undefined}

Z tego powodu pole wejściowe stanie się niekontrolowane.

Po wprowadzeniu dowolnej wartości na wejściu fieldsstan zmienia się na:

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

W tym czasie pole wejściowe zostaje przekształcone w kontrolowany komponent; dlatego pojawia się błąd:

Komponent zmienia niekontrolowane wprowadzanie tekstu tekstowego, który ma być kontrolowany.

Możliwe rozwiązania:

1- Zdefiniuj fieldsstan w:

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

2- Lub zdefiniuj właściwość wartości za pomocą oceny zwarcia w następujący sposób:

value={this.state.fields.name || ''}   // (undefined || '') = ''
Mayank Shukla
źródło
5
czy istnieje nieokreślony powód, który jest „niekontrolowany”, podczas gdy ten drugi jest „kontrolowany” - co one oznaczają?
Prashanth Subramanian
2
ponieważ ''jest poprawną wartością ciągu. więc kiedy zmienisz ''na „xyz”, typ danych wejściowych nie zmienia środków kontrolowanych na kontrolowane. Jednak w przypadku undefineddo xyzrodzaju zmieni się z niekontrolowanym do kontrolowany.
Mayank Shukla
1
Dziękuję, że to zadziałało dla mnie:value={this.state.fields.name || ''}
Bob
1
Nie wiedziałem, że gdy wartość stanie się niezdefiniowana, dane wejściowe zostaną automatycznie niekontrolowane, Świetnie. Naprawiłem już mój problem
Adrian Serna
1
niesamowity! ponieważ nie widziałem tego w oficjalnych dokumentach, czy jestem ślepy? link do źródła proszę :)
Dheeraj
34

Zmiana valuena defaultValueto rozwiąże.

Uwaga :

defaultValuejest tylko dla początkowego obciążenia. Jeśli chcesz zainicjować input, powinieneś użyć defaultValue, ale jeśli chcesz użyć statedo zmiany wartości, musisz użyć value. Przeczytaj to, aby uzyskać więcej.

Kiedyś value={this.state.input ||""}w inputpozbyć się tego ostrzeżenia.

MoFoLuWaSo
źródło
2
Dziękuję Ci! Natknąłem się na ten problem i inne rozwiązania mnie nie dotyczyły, ale to rozwiązanie pomogło.
PepperAddict
14

Wewnątrz komponentu umieść pole wprowadzania w następujący sposób.

<input className="class-name"
              type= "text"
              id="id-123"
              value={ this.state.value || "" }
              name="field-name"
              placeholder="Enter Name"
              />
Tabish
źródło
13

PO PROSTU, najpierw musisz ustawić stan początkowy

Jeśli nie ustawisz stanu początkowego, zareaguj potraktuje to jako niekontrolowany komponent

Vaibhav Bacchav
źródło
10

Oprócz zaakceptowanej odpowiedzi, jeśli używasz inputtypu checkboxlub radio, stwierdziłem, że muszę również zerować / niezdefiniować sprawdzenie checkedatrybutu.

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

A jeśli używasz TS (lub Babel), możesz użyć zerowego koalescencji zamiast logicznego operatora OR:

value={myStateValue ?? ''}
checked={someBoolean ?? false}
Lynden Noye
źródło
8

Najpierw ustaw bieżący stan ...this.state

Dzieje się tak, ponieważ gdy zamierzasz przypisać nowy stan, może on być niezdefiniowany. więc zostanie to naprawione poprzez ustawienie stanu wyodrębniania bieżącego stanu również

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

Jeśli w twoim stanie jest obiekt, powinieneś ustawić go w następujący sposób, załóżmy, że musisz ustawić nazwę użytkownika wewnątrz obiektu użytkownika.

this.setState({user:{...this.state.user, ['username']: username}})
NuOne
źródło
1
O ile rozumiem, setState już tylko zastępuje pola, więc w pierwszym przypadku przypisanie destrukcji nie powinno być konieczne. W drugim stanie może być konieczne, ponieważ setState zastąpi hurtownie podobiekt.
Kzqai
6
const [name, setName] = useState()

generuje błąd, gdy tylko wpiszesz w polu tekstowym

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

naprawi problem na tym przykładzie ciągu.

Nelles
źródło
2

Jeśli używasz wielu danych wejściowych w polu, wykonaj następujące czynności: Na przykład:

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

Wyszukaj swój problem na:

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
źródło
1

Używając React Hook również nie zapomnij ustawić wartości początkowej.
Używałem <input type='datetime-local' value={eventStart} />i początkowy eventStartbył jak

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

Pusty ciąg w nawiasach to różnica.
Ponadto, jeśli zresetujesz formularz po przesłaniu, tak jak ja, ponownie musisz ustawić go jako pusty ciąg, a nie tylko puste nawiasy.

To tylko mój mały wkład w ten temat, może komuś pomoże.

Zrna
źródło
0

W moim przypadku było tak, jak mówi najlepsza odpowiedź Mayanka Shukli. Jedynym szczegółem było to, że w moim stanie brakowało całkowicie właściwości, którą definiowałem.

Na przykład, jeśli masz ten stan:

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

Jeśli rozwijasz swój kod, możesz dodać nowy rekwizyt, więc w innym miejscu w kodzie możesz utworzyć nową właściwość, cktórej wartość jest nie tylko niezdefiniowana w stanie składnika, ale sama właściwość jest niezdefiniowana.

Aby rozwiązać ten problem, po prostu dodaj cdo swojego stanu i nadaj mu odpowiednią wartość początkową.

na przykład,

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

Mam nadzieję, że udało mi się wyjaśnić mój przypadek.

Daniel Segura
źródło
0

Otrzymuję to samo ostrzeżenie: komponent zmienia niekontrolowane dane wejściowe typu ukryte, aby je kontrolować. Nie mogę naprawić mojego problemu. Jakieś pomysły, dlaczego?

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>

próbowałem ({ valueName, valueName: {geschlecht=""}, onChangeAllg,})ivalue={valueName.geschlecht || ""}

Dr Malte Westerloh
źródło
znalazłem to. defaultValue={""}Wewnątrz TextField brakowało
dr Malte Westerloh
0

Ostrzeżenie: składnik zmienia niekontrolowane wprowadzanie tekstu tekstowego, który ma być kontrolowany. Elementy wejściowe nie powinny przełączać się z niekontrolowanego na kontrolowane (lub odwrotnie). Wybierz pomiędzy użyciem kontrolowanego lub niekontrolowanego elementu wejściowego przez cały okres użytkowania komponentu.

Rozwiązanie: Sprawdź, czy wartość nie jest niezdefiniowana

React / Formik / Bootstrap / TypeScript

przykład:

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
użytkownik3706761
źródło