Come ottenere il valore di un campo di input usando ReactJS?


189

Ho il seguente 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 console mi sta dando undefined- qualche idea di cosa c'è che non va in questo codice?


7
this.onSubmit.bind(this);
zerkms,

Bello - voglio aggiungerlo come risposta e lo
segnerò

2
che dire e.target.valuesenza il legame?
omarjmh,

1
e.target.value non sceglierebbe come target il pulsante, non il campo di input?
JoeTidee,

È necessario associare il onSubmitmetodo al pulsante di invio (elemento DOM) quando si fa clic (ovvero onClick={this.onSubmit.bind(this)}). E se desideri accedere al valore dell'input del titolo nel modulo che puoi utilizzare onSubmit(event) { const title = event.target.elements.title.value; }.
tfmontague,

Risposte:


10

È necessario utilizzare il costruttore sotto la classe MyComponent estende React.Component

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

Quindi otterrai il risultato del titolo


316

Ci sono tre risposte qui, a seconda della versione di React con cui sei (costretto a) lavorare (ing) e se vuoi usare gli hook.

Cominciando dall'inizio:

E 'importante capire come React lavori, in modo da poter fare le cose per bene (PROTIP: si tratta di è eccellente pena in esecuzione attraverso la Reagire esercizio tutorial sul sito Reagire E' ben scritto, e copre tutte le basi in modo che in realtà spiega come fare. cose). "Correttamente" qui significa che stai scrivendo un'interfaccia dell'applicazione che sembra essere visualizzata in un browser; tutto il lavoro dell'interfaccia avviene in React, non in "quello a cui sei abituato se stai scrivendo una pagina web" (ecco perché le app React sono "app", non "pagine web").

Le applicazioni React sono rese in base a due cose:

  1. le proprietà del componente dichiarate dal genitore crea un'istanza di quel componente, che il genitore può modificare durante il suo ciclo di vita, e
  2. lo stato interno del componente, che può modificarsi durante il suo intero ciclo di vita.

Quello che stai esplicitamente non fare quando si utilizza reagire sta generando elementi HTML e quindi utilizzando quelli: quando dite Reagire ad utilizzare un <input>, per esempio, si sta non crea un elemento di input HTML, si indica reagire a creare un oggetto di input Reagire che viene visualizzato come elemento di input HTML e la cui gestione degli eventi guarda, ma non è controllato da , gli eventi di input dell'elemento HTML.

Quando si utilizza React, ciò che si sta facendo è generare elementi dell'interfaccia utente dell'applicazione che presentano all'utente dati (spesso manipolabili), con l'interazione dell'utente che modifica lo stato del componente, il che può causare un rendering di una parte dell'interfaccia dell'applicazione in modo da riflettere il nuovo stato. In questo modello, lo stato è sempre l'autorità finale, non "qualunque sia la libreria dell'interfaccia utente utilizzata per renderlo", che sul Web è il DOM del browser. Il DOM è quasi un ripensamento in questo modello di programmazione: è solo il particolare framework dell'interfaccia utente che React utilizza.

Quindi, nel caso di un elemento di input, la logica è:

  1. Si digita l'elemento di input,
  2. non succede ancora nulla al tuo elemento di input, l'evento è stato intercettato da React e ucciso immediatamente ,
  3. React inoltra l'evento alla funzione che hai impostato per la gestione degli eventi,
  4. tale funzione può programmare un aggiornamento dello stato,
  5. in tal caso, React esegue tale aggiornamento di stato (in modo asincrono!) e attiverà una renderchiamata dopo l'aggiornamento, ma solo se l'aggiornamento di stato ha cambiato lo stato.
  6. solo dopo aver eseguito questo rendering l'interfaccia utente mostrerà che "hai digitato una lettera".

Tutto ciò accade in pochi millisecondi, se non di meno, quindi sembra che tu abbia digitato l'elemento di input nello stesso modo in cui sei abituato a "semplicemente usare un elemento di input in una pagina", ma non è assolutamente quello è accaduto.

Quindi, detto questo, su come ottenere valori dagli elementi in React:

Reagire 15 e sotto, con ES5

Per fare le cose correttamente, il tuo componente ha un valore di stato, che viene mostrato tramite un campo di input, e possiamo aggiornarlo facendo in modo che l'elemento UI rispedisca gli eventi di modifica nel 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
    });
  }
});

Quindi diciamo a reagire a utilizzare la updateInputValuefunzione per gestire l'interazione con l'utente, l'uso setStatedi programmare l'aggiornamento di stato, e il fatto che renderattinge this.state.inputValuesignifica che quando si rigenera dopo l'aggiornamento dello stato, l'utente vedrà il testo di aggiornamento in base a quello che digitate.

addendum basato su commenti

Dato che gli input dell'interfaccia utente rappresentano valori di stato (considera cosa succede se un utente chiude la sua scheda a metà strada e la scheda viene ripristinata. Dovrebbero essere ripristinati tutti quei valori che hanno inserito? In tal caso, quello è lo stato). Ciò potrebbe farti sentire come se un modulo di grandi dimensioni avesse bisogno di decine o anche di un centinaio di moduli di input, ma React riguarda la modellazione dell'interfaccia utente in modo sostenibile: non hai 100 campi di input indipendenti, hai gruppi di input correlati, quindi acquisisci ciascuno raggruppare in un componente e quindi creare il modulo "master" come una raccolta di gruppi.

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

Questo è anche molto più facile da mantenere rispetto a un componente gigante a forma singola. Suddividi i gruppi in Componenti con manutenzione dello stato, in cui ciascun componente è responsabile solo del monitoraggio di alcuni campi di input alla volta.

Potresti anche pensare che sia "una seccatura" scrivere tutto quel codice, ma si tratta di un falso risparmio: gli sviluppatori-che-non-sei-te, incluso il futuro, traggono grandi benefici dal vedere tutti quegli input collegati esplicitamente, perché rende molto più facile tracciare i percorsi del codice. Tuttavia, puoi sempre ottimizzare. Ad esempio, puoi scrivere un linker di stato

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']}/>
    });
  }
});

Naturalmente, ci sono versioni migliorate di questo, quindi vai su https://npmjs.com e cerca una soluzione di collegamento dello stato React che ti piace di più. L'open source riguarda principalmente la ricerca di ciò che gli altri hanno già fatto e l'utilizzo di questo invece di scrivere tutto da soli.

Reagisci 16 (e 15,5 di transizione) e JS "moderno"

A partire da React 16 (e soft-start con 15.5) la createClasschiamata non è più supportata e deve essere utilizzata la sintassi della classe. Questo cambia due cose: la sintassi della classe ovvia, ma anche l' thisassociazione del contesto che createClasspuò fare "gratis", quindi per assicurarti che le cose continuino a funzionare assicurati di usare la notazione "fat arrow" per thispreservare le funzioni anonime nei onWhatevergestori, come il onChangeche usiamo nel codice qui:

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

Potresti anche aver visto le persone usare bindnel loro costruttore per tutte le loro funzioni di gestione degli eventi, come questo:

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

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

Non farlo.

Quasi ogni volta che stai usando bind, si applica il proverbiale "stai sbagliando". La tua classe definisce già il prototipo dell'oggetto e quindi già definisce il contesto dell'istanza. Non aggiungere a bindquello; utilizzare il normale inoltro di eventi invece di duplicare tutte le chiamate di funzione nel costruttore, poiché tale duplicazione aumenta la superficie del bug e rende molto più difficile tracciare gli errori perché il problema potrebbe essere nel costruttore anziché nel punto in cui si chiama il codice. Oltre a porre un onere di manutenzione sugli altri con cui (hai o scegli) lavorare.

Sì, so che i documenti di reazione dicono che va bene. Non lo è, non farlo.

Reagire 16.8, utilizzando i componenti di funzione con ganci

A partire da React 16.8 il componente della funzione (cioè letteralmente solo una funzione che accetta alcuni propsargomenti può essere usato come se fosse un'istanza di una classe componente, senza mai scrivere una classe) può anche essere dato stato, attraverso l'uso di hook .

Se non hai bisogno di un codice di classe completo, e una funzione di singola istanza lo farà, allora puoi usare l' useStatehook per ottenere una singola variabile di stato e la sua funzione di aggiornamento, che funziona più o meno come negli esempi precedenti, tranne senza la setStatechiamata di funzione:

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

In precedenza la distinzione non ufficiale tra classi e componenti di funzione era "i componenti di funzione non hanno stato", quindi non possiamo più nasconderci dietro quello: la differenza tra componenti di funzione e componenti di classi può essere trovata diffusa su diverse pagine nel documentazione di reazione scritta (nessuna scorciatoia una spiegazione di copertina per interpretare erroneamente per te!) che dovresti leggere in modo da sapere cosa stai facendo e quindi sapere se hai scelto la soluzione migliore (qualunque cosa significhi per te) per programmare te stesso per un problema che stai riscontrando.


4
Ho letto alcuni articoli online che affermano che usare troppo stato è una cattiva idea. In una forma particolare della mia domanda ho circa 100 campi modulo. Definire una funzione per salvare lo stato sembra un modo inutilmente arduo di fare le cose. Se posso usare onClick = {this.onSubmit.bind (this)}, questo sembra un buon modo per ottenere il valore (quindi se voglio, imposta lo stato dei componenti) - Gradirei alcuni commenti su questo.
JoeTidee,

5
quindi scrivi un codice più intelligente. gli input del modulo sono sicuramente stati (considera cosa succede se un utente chiude la sua scheda a metà strada e la scheda viene ripristinata. Dovrebbero essere ripristinati tutti quei valori che hanno inserito? sì? questo è stato ), quindi scrivi un po 'di codice di manutenzione dello stato. Anche Facebook ha centinaia di valori di forma e la loro soluzione alla follia è stata React. Funziona davvero bene. Un modo per rendere il tuo codice un po 'più semplice, mentre usi ancora lo stato, è usare il collegamento dello stato a due vie , ancora una volta, spiegato sul sito React. Vale la pena leggere! =)
Mike 'Pomax' Kamermans,

2
Si noti inoltre che "100 campi" è per lo più irrilevante: suddividere il modulo, perché non è 100 elementi, è diverse sezioni, ognuna con un numero di input, quindi applicare un buon design e rendere ogni sezione il proprio componente, raggruppando i componenti per il modulo gruppi. Questo in genere rende un componente responsabile di meno di 10 input e improvvisamente la tua architettura delle informazioni ha molto più senso. Il modulo di invio, come azione del browser, ovviamente vede solo "il tuo modulo" e invia tutto in una volta sola. Design dell'interfaccia utente pulito e mirato.
Mike 'Pomax' Kamermans,

2
Grazie per i commenti Ho notato tuttavia che il collegamento tra stati è stato deprecato a partire da React v15.
JoeTidee,

3
@JasonChing allora hai semplicemente inserito potenziali bug nel tuo codice. Reagire non è un "essere tutti, finiscono tutti" soluzione per le pagine web, si tratta di un quadro di riferimento per la creazione di interfacce, e che è responsabile della gestione dello stato e il rendering dell'interfaccia utente attuale ripensamento (gli utenti non interagiscono con il DOM, in cui interagiscono con React. Gli aggiornamenti DOM sono semplicemente un ultimo passo asincrono (ma incredibilmente veloce) in modo che l'interfaccia utente rifletta visivamente lo stato). Se vuoi aggirarlo, la domanda più importante è: perché stai usando React? Perché il miglior segno che stai usando in modo sbagliato è combinare React e jQuery.
Mike 'Pomax' Kamermans,

17

Gestito per ottenere il valore del campo di input facendo qualcosa del genere:

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

1
Perché usare "setState"? Ciò comporta un nuovo rendering ... non è vero?
Luca Davanzo,

15

Nella reazione 16, uso

<Input id="number" 
       type="time" 
       onChange={(evt) => { console.log(evt.target.value); }} />

non funziona se il campo è stato
compilato

4

Sono riuscito a farlo associando "questo" alla funzione updateInputValue (evt) con

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

Tuttavia, il valore di input = {this.state.inputValue} ... non è stato una buona idea.

Ecco il codice completo in 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;
   }
}

2

il tuo errore è dovuto al fatto che usi la classe e quando usi la classe dobbiamo legare le funzioni con This per funzionare bene. comunque ci sono molti tutorial per cui dovremmo "questo" e cosa è "questo" fare in javascript.

se correggi il tuo pulsante di invio dovrebbe funzionare:

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

e anche se vuoi mostrare il valore di quell'input nella console dovresti usare var title = this.title.value;


2
questo link potrebbe essere utile se vuoi saperne di più su "this"
Soroush Bk,


2

Dai <input>un ID unico

<input id='title' ...>

e quindi utilizzare l' API Web standard per fare riferimento a esso nel DOM

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

Non è necessario aggiornare continuamente lo stato React ad ogni pressione di un tasto. Ottieni semplicemente il valore quando è richiesto.


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="johdoe@somewhere.com" />

mentre la tua risposta potrebbe essere buona per la domanda, è sempre meglio aggiungere qualche spiegazione. Si prega di prendere 2 minuti per aggiungerlo. Ciò migliorerà la tua risposta anche per i futuri utenti.
DaFois,

certo, lo farò.
Kidali Kevin,

0

È possibile ottenere un valore di input senza aggiungere la funzione 'onChange'.

Aggiungi all'elemento di input un 'ref attr:

E quindi usa this.refs per ottenere il valore di input quando ne hai bisogno.


3
Questo non è più raccomandato.
Joe Tidee,

1
Puoi usarli, ma si consiglia di mantenere il flusso di dati in una direzione usando oggetti di scena e callback.
Joe Tidee,

Sarebbe bene aggiungere un esempio di aggiunta corretta di ref, vale a dire l'utilizzo di un callback ref anziché una stringa legacy.
Joe Tidee,

0

Cambia il tuo ref in: ref='title'ed elimina name='title' Quindi elimina var title = this.titlee scrivi:

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

Inoltre dovresti aggiungere .bind(this)athis.onSubmit

(Ha funzionato nel mio caso che era abbastanza simile, ma invece onClickche avevo onSubmit={...}ed è stato messo in forma ( <form onSubmit={...} ></form>))


0

se si utilizza il componente di classe, solo 3 passaggi: prima è necessario dichiarare lo stato per l'input archiviato, ad esempio this.state = {name: ''} . In secondo luogo, è necessario scrivere una funzione per impostare lo stato quando cambia nell'esempio seguente è setName () e infine è necessario scrivere l'input jsx ad esempio <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

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

};

0

utilizzando campi non controllati:

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

};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.