¿Cómo obtener el valor de un campo de entrada usando ReactJS?

190

Tengo el siguiente componente React:

export default class MyComponent extends React.Component {

    onSubmit(e) {
        e.preventDefault();
        var title = this.title;
        console.log(title);
    }

    render(){
        return (
            ...
            <form className="form-horizontal">
                ...
                <input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
                ...
            </form>
            ...
            <button type="button" onClick={this.onSubmit} className="btn">Save</button>
            ...
        );
    }

};

La consola me está dando, ¿ undefinedalguna idea de lo que está mal con este código?

JoeTidee
fuente
77
this.onSubmit.bind(this);
zerkms
Agradable: quiero agregarlo como respuesta y lo
marcaré
2
¿Qué pasa e.target.valuesin la atadura?
omarjmh
1
¿no estaría e.target.value apuntando al botón, no al campo de entrada?
JoeTidee
Debe vincular el onSubmitmétodo al botón de envío (elemento DOM) al hacer clic (es decir onClick={this.onSubmit.bind(this)}). Y si desea acceder al valor de la entrada del título en el formulario que puede usar onSubmit(event) { const title = event.target.elements.title.value; }.
tfmontague

Respuestas:

11

Debe usar el constructor bajo la clase MyComponent extiende React.Component

constructor(props){
    super(props);
    this.onSubmit = this.onSubmit.bind(this);
  }

Entonces obtendrás el resultado del título

Md. Maidul Islam
fuente
317

Aquí hay tres respuestas, dependiendo de la versión de React con la que estés (forzado) a trabajar (ing) y de si quieres usar ganchos.

Lo primero es lo primero:

Es importante entender cómo reaccionan los trabajos, por lo que puede hacer las cosas bien (protip: es es súper pena correr a través de la Reaccionar ejercicio tutorial en el sitio web Reaccionar Está bien escrito, y cubre todos los aspectos básicos de una manera que explica realmente cómo hacerlo. cosas). "Correctamente" aquí significa que está escribiendo una interfaz de aplicación que se representa en un navegador; todo el trabajo de interfaz ocurre en React, no en "a lo que estás acostumbrado si estás escribiendo una página web" (es por eso que las aplicaciones React son "aplicaciones", no "páginas web").

Las aplicaciones de reacción se representan en base a dos cosas:

  1. las propiedades del componente según lo declarado por cualquier padre que cree una instancia de ese componente, que el padre puede modificar a lo largo de su ciclo de vida, y
  2. El propio estado interno del componente, que puede modificarse a lo largo de su propio ciclo de vida.

Lo que está expresamente no hacerlo cuando utiliza Reaccionar está generando elementos HTML y luego usando los: cuando le dices a reaccionar a utilizar una <input>, por ejemplo, que está no crear un elemento de entrada HTML, le está diciendo reaccionan para crear un objeto de entrada Reaccionar eso pasa a representarse como un elemento de entrada HTML, y cuyo manejo de eventos observa, pero no está controlado por , los eventos de entrada del elemento HTML.

Cuando usa React, lo que está haciendo es generar elementos de la interfaz de usuario de la aplicación que presenten al usuario datos (a menudo manipulables), con la interacción del usuario cambiando el estado del Componente, lo que puede provocar que una parte de la interfaz de la aplicación refleje el nuevo estado. En este modelo, el estado es siempre la autoridad final, no "cualquier biblioteca de IU que se use para representarla", que en la web es el DOM del navegador. El DOM es casi una ocurrencia tardía en este modelo de programación: es solo el marco de UI particular que React está usando.

Entonces, en el caso de un elemento de entrada, la lógica es:

  1. Escribe el elemento de entrada,
  2. todavía no le sucede nada a su elemento de entrada, el evento fue interceptado por React y se eliminó de inmediato ,
  3. Reaccionar reenvía el evento a la función que ha configurado para el manejo de eventos,
  4. esa función puede programar una actualización de estado,
  5. si lo hace, React ejecuta esa actualización de estado (¡asincrónicamente!) y activará una renderllamada después de la actualización, pero solo si la actualización de estado cambió el estado.
  6. solo después de que se haya realizado este procesamiento, la interfaz de usuario mostrará que "escribió una letra".

Todo eso sucede en cuestión de milisegundos, si no menos, por lo que parece que tecleaste en el elemento de entrada de la misma manera que estás acostumbrado a "simplemente usando un elemento de entrada en una página", pero eso no es absolutamente lo que sucedió

Entonces, dicho esto, sobre cómo obtener valores de elementos en React:

Reacciona 15 y menos, con ES5

Para hacer las cosas correctamente, su componente tiene un valor de estado, que se muestra a través de un campo de entrada, y podemos actualizarlo haciendo que ese elemento de la interfaz de usuario envíe eventos de cambio nuevamente al componente:

var Component = React.createClass({
  getInitialState: function() {
    return {
      inputValue: ''
    };
  },

  render: function() {
    return (
      //...
      <input value={this.state.inputValue} onChange={this.updateInputValue}/>
      //...
    );
  },

  updateInputValue: function(evt) {
    this.setState({
      inputValue: evt.target.value
    });
  }
});

Por lo tanto, le decimos a React que use la updateInputValuefunción para manejar la interacción del usuario, use setStatepara programar la actualización de estado, y el hecho de que renderaproveche this.state.inputValuesignifica que cuando vuelve a funcionar después de actualizar el estado, el usuario verá el texto de actualización en función de lo que escribió.

Anexo basado en comentarios

Dado que las entradas de la IU representan valores de estado (considere lo que sucede si un usuario cierra su pestaña a mitad de camino y la pestaña se restaura. ¿Deberían restaurarse todos esos valores que completaron? Si es así, ese es el estado). Eso podría hacerte sentir que un formulario grande necesita decenas o incluso cien formularios de entrada, pero React se trata de modelar tu IU de una manera sostenible: no tienes 100 campos de entrada independientes, tienes grupos de entradas relacionadas, por lo que capturas cada uno agrupe en un componente y luego cree su formulario "maestro" como una colección de grupos.

MyForm:
  render:
    <PersonalData/>
    <AppPreferences/>
    <ThirdParty/>
     ...

Esto también es mucho más fácil de mantener que un componente gigante de forma única. Divida los grupos en Componentes con mantenimiento de estado, donde cada componente solo es responsable de rastrear algunos campos de entrada a la vez.

También puede sentir que es "una molestia" escribir todo ese código, pero eso es un falso ahorro: los desarrolladores que no son usted, incluido el futuro, realmente se benefician enormemente al ver todas esas entradas conectadas explícitamente, porque hace que las rutas de código sean mucho más fáciles de rastrear. Sin embargo, siempre puedes optimizar. Por ejemplo, puedes escribir un enlazador de estado

MyComponent = React.createClass({
  getInitialState() {
    return {
      firstName: this.props.firstName || "",
      lastName: this.props.lastName || "" 
      ...: ...
      ...
    }
  },
  componentWillMount() {
    Object.keys(this.state).forEach(n => {
      let fn = n + 'Changed';
      this[fn] = evt => {
        let update = {};
        update[n] = evt.target.value;
        this.setState(update);
      });
    });
  },
  render: function() {
    return Object.keys(this.state).map(n => {
      <input
        key={n} 
        type="text"
        value={this.state[n]}
        onChange={this[n + 'Changed']}/>
    });
  }
});

Por supuesto, hay versiones mejoradas de esto, así que visite https://npmjs.com y busque la solución de enlace de estado React que más le guste. El código abierto se trata principalmente de encontrar lo que otros ya han hecho y usarlo en lugar de escribir todo usted mismo desde cero.

Reacciona 16 (y 15.5 de transición) y JS 'moderno'

A partir de React 16 (y de inicio suave con 15.5), la createClassllamada ya no es compatible y es necesario utilizar la sintaxis de clase. Esto cambia dos cosas: la sintaxis de clase obvia, pero también el thisenlace de contexto que se createClasspuede hacer "gratis", así que para asegurarse de que las cosas sigan funcionando, asegúrese de estar usando la notación de "flecha gruesa" para el thiscontexto que conserva funciones anónimas en los onWhatevercontroladores, como la onChangeusamos en el código aquí:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: ''
    };
  }

  render() {
    return (
      //...
      <input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
      //...
    );
  },

  updateInputValue(evt) {
    this.setState({
      inputValue: evt.target.value
    });
  }
});

También es posible que haya visto a personas usar binden su constructor para todas sus funciones de manejo de eventos, como esta:

constructor(props) {
  super(props);
  this.handler = this.handler.bind(this);
  ...
}

render() {
  return (
    ...
    <element onclick={this.handler}/>
    ...
  );
}

No hagas eso.

Casi cada vez que está usando bind, se aplica el proverbial "lo estás haciendo mal". Su clase ya define el prototipo del objeto y, por lo tanto, ya define el contexto de la instancia. No pongas bindencima de eso; use el reenvío de eventos normal en lugar de duplicar todas sus llamadas de función en el constructor, porque esa duplicación aumenta la superficie de su error y hace que sea mucho más difícil rastrear errores porque el problema podría estar en su constructor en lugar de donde llama su código. Además de imponer una carga de mantenimiento a otros con los que usted (tiene o elige) trabajar.

Sí, sé que los documentos de reacción dicen que está bien. No lo es, no lo hagas.

Reacciona 16.8, usando componentes de función con ganchos

A partir de React 16.8, el componente de función (es decir, literalmente solo una función que toma algo propscomo argumento se puede usar como si fuera una instancia de una clase de componente, sin escribir nunca una clase) también se le puede dar estado, mediante el uso de ganchos .

Si no necesita un código de clase completo, y una función de instancia única servirá, ahora puede usar el useStateenlace para obtener una sola variable de estado y su función de actualización, que funciona más o menos igual que los ejemplos anteriores, excepto sin la setStatellamada a la función:

import { useState } from 'react';

function myFunctionalComponentFunction() {
  const [input, setInput] = useState(''); // '' is the initial state value
  return (
    <div>
    <label>Please specify:</label>
    <input value={input} onInput={e => setInput(e.target.value)}/>
    </div>
  );
}

Anteriormente, la distinción no oficial entre las clases y los componentes de la función era "los componentes de la función no tienen estado", por lo que ya no podemos escondernos detrás de eso: la diferencia entre los componentes de la función y los componentes de las clases se puede encontrar en varias páginas muy bien. documentación de reacción escrita (sin acceso directo, una explicación de línea para malinterpretar convenientemente para usted) que debe leer para saber lo que está haciendo y así saber si eligió la mejor solución (lo que sea que eso signifique para usted) para programarlo usted mismo por un problema que tienes

Mike 'Pomax' Kamermans
fuente
44
He leído algunos artículos en línea que dicen que usar demasiado estado es una mala idea. En una forma particular de mi aplicación, tengo alrededor de 100 campos de formulario. Definir una función para salvar el estado se siente como una forma innecesariamente ardua de hacer las cosas. Si puedo usar onClick = {this.onSubmit.bind (this)}, esta parece ser una buena manera de obtener el valor (luego, si lo deseo, establezca el estado de los componentes). Agradecería algunos comentarios al respecto.
JoeTidee
55
así que escribe un código más inteligente. las entradas de formulario son definitivamente estado (considere lo que sucede si un usuario cierra su pestaña a mitad de camino y la pestaña se restaura. ¿Deberían restaurarse todos esos valores que completaron? ¿Sí? ese es el estado ), así que escriba un poco de código de mantenimiento de estado. Facebook también tiene cientos de valores de forma, y ​​su solución a la locura fue Reaccionar. Funciona muy bien Una forma de hacer que su código sea un poco más fácil, mientras aún usa el estado, es usar el enlace de estado bidireccional , nuevamente, explicado en el sitio React. ¡Vale la pena leer! =)
Mike 'Pomax' Kamermans
2
También tenga en cuenta que "100 campos" es sobre todo irrelevante: divida su formulario, porque no son 100 elementos, son varias secciones, cada una con una cantidad de entradas, así que aplique un buen diseño y haga que cada sección sea su propio componente, con componentes de agrupación para el formulario grupos Esto generalmente hace que un componente sea responsable de menos de 10 entradas, y de repente su arquitectura de información tiene mucho más sentido. El envío del formulario, como acción del navegador, por supuesto solo ve "su formulario" y envía todo de una vez. Diseño de interfaz de usuario limpio y dirigido.
Mike 'Pomax' Kamermans
2
Gracias por los comentarios. Sin embargo, noté que la vinculación de estado ha quedado en desuso a partir de React v15.
JoeTidee
3
@JasonChing, entonces simplemente ha incorporado posibles errores en su código. Reaccionar no es un "ser todo, poner fin a toda" solución a páginas web, que es un marco para la creación de interfaces, y que es responsable de la administración del estado y la representación de interfaz de usuario real como ocurrencia tardía (a los usuarios no interactúan con el DOM, que interactúan con Reaccionar: las actualizaciones DOM son simplemente un último paso asíncrono (pero increíblemente rápido) para que la IU refleje visualmente el estado). Si quieres evitar eso, la pregunta más importante es: ¿por qué estás usando React? Porque la mejor señal de que lo estás usando mal es combinar React y jQuery.
Mike 'Pomax' Kamermans
17

Logramos obtener el valor del campo de entrada haciendo algo como esto:

import React, { Component } from 'react';

class App extends Component {

constructor(props){
super(props);

this.state = {
  username : ''
}

this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}


updateInput(event){
this.setState({username : event.target.value})
}


handleSubmit(){
console.log('Your input value is: ' + this.state.username)
//Send state to the server code
}



render(){
return (
    <div>
    <input type="text" onChange={this.updateInput}></input>
    <input type="submit" onClick={this.handleSubmit} ></input>
    </div>
  );
}
} 

//output
//Your input value is: x
Hugo Wesley
fuente
1
¿Por qué usar "setState"? Esto implica una nueva representación ... ¿no?
Luca Davanzo
15

En reaccionar 16, yo uso

<Input id="number" 
       type="time" 
       onChange={(evt) => { console.log(evt.target.value); }} />
Pyae Sone
fuente
no funciona si el campo se rellena automáticamente con la carga de edad
SeanMC
4

Logré hacerlo vinculando el "this" a la función updateInputValue (evt) con

this.updateInputValue = this.updateInputValue.bind (this);

Sin embargo, el valor de entrada = {this.state.inputValue} ... resultó no ser una buena idea.

Aquí está el código completo en babel ES6:

class InputField extends React.Component{


  constructor(props){
   super(props);
   //this.state={inputfield: "no value"};   
   this.handleClick = this.handleClick.bind(this);
   this.updateInputValue = this.updateInputValue.bind(this);
  }

  handleClick(){
   console.log("trying to add picture url");
   console.log("value of input field : "+this.state.inputfield);

  }

  updateInputValue(evt){
    //console.log("input field updated with "+evt.target.value);
    this.state={inputfield: evt.target.value};   

  }

  render(){
    var r; 
    r=<div><input type="text" id="addpixinputfield" 
            onChange={this.updateInputValue} />
      <input type="button" value="add" id="addpix" onClick={this.handleClick}/>
      </div>;    
    return r;
   }
}
Matthias Liszt
fuente
2

su error se debe a que usa class y cuando usa class necesitamos vincular las funciones con This para que funcione bien. de todos modos hay muchos tutoriales sobre por qué deberíamos "esto" y qué es "esto" hacer en javascript.

si corrige su botón de envío, debería funcionar:

<button type="button" onClick={this.onSubmit.bind(this)} className="btn">Save</button>

y también si desea mostrar el valor de esa entrada en la consola, debe usar var title = this.title.value;

Soroush Bk
fuente
2
este enlace puede ser útil si quieres saber más sobre "esto"
Soroush Bk
2

Dale <input>una identificación única

<input id='title' ...>

y luego use la API web estándar para referenciarla en el DOM

const title = document.getElementById('title').value

No es necesario actualizar continuamente el estado Reaccionar con cada pulsación de tecla. Simplemente obtenga el valor cuando sea necesario.

Brent Washburne
fuente
1
// On the state
constructor() {
  this.state = {
   email: ''
 }
}

// Input view ( always check if property is available in state {this.state.email ? this.state.email : ''}

<Input 
  value={this.state.email ? this.state.email : ''} 
  onChange={event => this.setState({ email: event.target.value)}
  type="text" 
  name="emailAddress" 
  placeholder="[email protected]" />

Kidali Kevin
fuente
Si bien su respuesta podría ser buena para la pregunta, siempre es mejor agregar alguna explicación. Tómese 2 minutos para agregarlo. Esto mejorará su respuesta también para futuros usuarios.
DaFois
Claro, lo haré.
Kidali Kevin
0

Puede obtener un valor de entrada sin agregar la función 'onChange'.

Simplemente agregue al elemento de entrada un 'ref attr:

Y luego use this.refs para obtener el valor de entrada cuando lo necesite.

E1ad
fuente
3
Esto ya no se recomienda.
JoeTidee
1
Puede usarlos, pero se recomienda mantener el flujo de datos en una dirección utilizando accesorios y devoluciones de llamada.
JoeTidee
Sería bueno agregar un ejemplo de agregar referencias correctamente, es decir, usar una devolución de llamada de referencia en lugar de una cadena heredada.
JoeTidee
0

Cambie su referencia a: ref='title'y elimine name='title' Luego elimine var title = this.titley escriba:

console.log(this.refs.title.value)

También deberías agregar .bind(this)athis.onSubmit

(Funcionó en mi caso que era bastante similar, pero en lugar de onClickque tenía onSubmit={...}y se puso en la forma ( <form onSubmit={...} ></form>))

Katarzyna Wrońska
fuente
0

si usa el componente de clase, entonces solo 3 pasos: primero debe declarar el estado de su entrada archivada, por ejemplo this.state = {name: ''} . En segundo lugar, debe escribir una función para establecer el estado cuando cambia en el siguiente ejemplo, es setName () y finalmente debe escribir la entrada jsx por ejemplo <input value = {this.name} onChange = {this.setName} />

import React, { Component } from 'react'

export class InputComponents extends Component {
    constructor(props) {
        super(props)

        this.state = {
             name:'',
             agree:false
        }
        this.setName = this.setName.bind(this);
        this.setAgree=this.setAgree.bind(this);
    }

    setName(e){
        e.preventDefault();
        console.log(e.target.value);
        this.setState({
            name:e.target.value
        })
    }
    setAgree(){
        this.setState({
            agree: !this.state.agree
        }, function (){
            console.log(this.state.agree);
        })
    }
    render() {
        return (
            <div>
                <input type="checkbox" checked={this.state.agree} onChange={this.setAgree}></input>
                < input value={this.state.name} onChange = {this.setName}/>
            </div>
        )
    }
}

export default InputComponents
Señor
fuente
0
export default class MyComponent extends React.Component {

onSubmit(e) {
    e.preventDefault();
    var title = this.title.value; //added .value
    console.log(title);
}

render(){
    return (
        ...
        <form className="form-horizontal">
            ...
            <input type="text" className="form-control" ref={input => this.title = input} name="title" />
            ...
        </form>
        ...
        <button type="button" onClick={this.onSubmit} className="btn">Save</button>
        ...
    );
}

};
Pranav Agarwal
fuente
0

utilizando campos no controlados:

export default class MyComponent extends React.Component {

    onSubmit(e) {
        e.preventDefault();
        console.log(e.target.neededField.value);
    }

    render(){
        return (
            ...
            <form onSubmit={this.onSubmit} className="form-horizontal">
                ...
                <input type="text" name="neededField" className="form-control" ref={(c) => this.title = c} name="title" />
                ...
            </form>
            ...
            <button type="button" className="btn">Save</button>
            ...
        );
    }

};
Georg
fuente