Un componente está cambiando una entrada no controlada de texto de tipo para controlar el error en ReactJS

332

Advertencia: Un componente está cambiando una entrada no controlada de texto de tipo a controlar. Los elementos de entrada no deben cambiar de no controlado a controlado (o viceversa). Decida entre usar un elemento de entrada controlado o no controlado durante la vida útil del componente. *

El siguiente es mi código:

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
fuente
2
¿Cuál es el valor inicial de fieldsen estado?
Mayank Shukla
2
constructor (accesorios) {super (accesorios); this.state = {campos: {}, errores: {}} this.onSubmit = this.onSubmit.bind (this); }
Riya Kapuria
2
Posible duplicado de React - cambio de una entrada no controlada
Michael Freidgeim

Respuestas:

651

La razón es que, en el estado que definiste:

this.state = { fields: {} }

campos como un objeto en blanco, por lo que durante la primera representación this.state.fields.nameserá undefined, y el campo de entrada obtendrá su valor como:

value={undefined}

Debido a eso, el campo de entrada quedará sin control.

Una vez que ingresa cualquier valor en la entrada, el fieldsestado cambia a:

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

Y en ese momento el campo de entrada se convierte en un componente controlado; es por eso que obtienes el error:

Un componente está cambiando una entrada no controlada de texto de tipo a controlar.

Soluciones posibles:

1- Defina el fieldsestado de entrada como:

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

2- O defina la propiedad de valor utilizando la evaluación de cortocircuito de esta manera:

value={this.state.fields.name || ''}   // (undefined || '') = ''
Mayank Shukla
fuente
55
¿hay alguna razón indefinida "no controlada" mientras que esta última está "controlada"? ¿Qué significan?
Prashanth Subramanian
2
porque ''es un valor de cadena válido. así que cuando cambia ''a 'xyz', el tipo de entrada no cambia significa controlado a controlado. Pero en caso de undefinedque xyzel tipo va a cambiar a partir incontrolada de control.
Mayank Shukla
1
Gracias, esto funcionó para mí:value={this.state.fields.name || ''}
Bob
1
No sabía que una vez que el valor se vuelve indefinido, la entrada se descontrola automáticamente, Genial. Ya solucioné mi problema
Adrian Serna
1
¡asombroso! porque no vi esto mencionado en los documentos oficiales, ¿o soy ciego? enlace a la fuente por favor :)
Dheeraj
34

Cambiar valuea defaultValuelo resolverá.

Nota :

defaultValuees solo para la carga inicial. Si desea inicializar, inputentonces debe usar defaultValue, pero si desea usar statepara cambiar el valor, entonces debe usar value. Lea esto para más.

He utilizado value={this.state.input ||""}en inputdeshacerse de esa advertencia.

MoFoLuWaSo
fuente
2
¡Gracias! Encontré este problema y las otras soluciones no se aplicaban a mí, pero esta solución ayudó.
PepperAddict
14

Dentro del componente coloque el cuadro de entrada de la siguiente manera.

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

SIMPLEMENTE, primero debe establecer el estado inicial

Si no configura el estado inicial, reaccionar lo tratará como un componente no controlado

Vaibhav Bacchav
fuente
10

Además de la respuesta aceptada, si está utilizando un inputtipo checkboxo radio, he descubierto que también necesito verificar el checkedatributo nulo / indefinido .

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

Y si está utilizando TS (o Babel), podría usar la fusión nula en lugar del operador lógico OR:

value={myStateValue ?? ''}
checked={someBoolean ?? false}
Lynden Noye
fuente
8

Establecer el estado actual primero ...this.state

Es porque cuando va a asignar un nuevo estado puede ser indefinido. por lo que se solucionará estableciendo el estado extrayendo el estado actual

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

Si hay un objeto en su estado, debe establecer el estado de la siguiente manera, supongamos que tiene que establecer el nombre de usuario dentro del objeto de usuario.

this.setState({user:{...this.state.user, ['username']: username}})
NuOne
fuente
1
Por lo que yo entiendo, setState ya solo anula los campos, por lo que en el primer caso no debería ser necesario desestructurar la asignación. En el segundo estado puede ser necesario ya que setState reemplazará un subobjeto al por mayor.
Kzqai
6
const [name, setName] = useState()

genera un error tan pronto como escribe en el campo de texto

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

solucionará el problema en este ejemplo de cadena.

Nelles
fuente
2

Si usa múltiples entradas en el campo, siga: Por ejemplo:

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

Busque su problema en:

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
fuente
1

El uso de React Hooks tampoco se olvida de establecer el valor inicial.
Estaba usando <input type='datetime-local' value={eventStart} />y la inicial eventStartera como

const [eventStart, setEventStart] = useState();
en su lugar
const [eventStart, setEventStart] = useState('');.

La cadena vacía entre paréntesis es la diferencia.
Además, si restablece el formulario después de enviarlo como lo hago, nuevamente debe establecerlo en una cadena vacía, no solo para vaciar los paréntesis.

Esta es solo mi pequeña contribución a este tema, tal vez ayude a alguien.

Zrna
fuente
0

En mi caso, fue más o menos lo que dice la respuesta principal de Mayank Shukla. El único detalle fue que mi estado carecía por completo de la propiedad que estaba definiendo.

Por ejemplo, si tiene este estado:

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

Si está expandiendo su código, es posible que desee agregar un nuevo accesorio, por lo tanto, en otro lugar en su código, puede crear una nueva propiedad ccuyo valor no solo esté indefinido en el estado del componente, sino que la propiedad en no esté definida.

Para resolver esto, solo asegúrese de agregar ca su estado y darle un valor inicial adecuado.

p.ej,

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

Espero haber podido explicar mi caso límite.

Daniel Segura
fuente
0

Recibo la misma advertencia: un componente está cambiando una entrada no controlada de tipo oculto para ser controlado. No puedo solucionar mi problema. Alguna idea de por qué?

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>

lo intenté ({ valueName, valueName: {geschlecht=""}, onChangeAllg,})yvalue={valueName.geschlecht || ""}

Dr. Malte Westerloh
fuente
Lo encontré. defaultValue={""}Faltaba un interior del TextField
Dr. Malte Westerloh
0

Advertencia: Un componente está cambiando una entrada no controlada de texto de tipo a controlar. Los elementos de entrada no deben cambiar de no controlado a controlado (o viceversa). Decida entre usar un elemento de entrada controlado o no controlado durante la vida útil del componente.

Solución: compruebe si el valor no está indefinido

Reaccionar / Formik / Bootstrap / TypeScript

ejemplo:

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
usuario3706761
fuente