Como obter o valor de um campo de entrada usando o ReactJS?

189

Eu tenho o seguinte 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>
            ...
        );
    }

};

O console está me dando undefined- alguma idéia do que há de errado com esse código?

JoeTidee
fonte
7
this.onSubmit.bind(this);
Zerkms
Nice - quer adicioná-lo como resposta e eu vou assinale-off (?)
JoeTidee
2
e e.target.valuesem o vínculo?
omarjmh
1
o e.target.value não estaria segmentando o botão, não o campo de entrada?
JoeTidee
Você precisa vincular o onSubmitmétodo ao botão de envio (elemento DOM) quando clicado (ou seja onClick={this.onSubmit.bind(this)}). E se você deseja acessar o valor da entrada do título no formulário, pode usar onSubmit(event) { const title = event.target.elements.title.value; }.
precisa saber é o seguinte

Respostas:

10

Você deve usar o construtor sob a classe MyComponent extends React.Component

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

Então você obterá o resultado do título

Md. Maidul Islam
fonte
316

Existem três respostas aqui, dependendo da versão do React com a qual você é forçado a trabalhar e se deseja usar ganchos.

Primeiras coisas primeiro:

É importante entender como Reagir obras, para que possa fazer as coisas corretamente (Protip: é é super- pena que atravessa a Reagir exercício tutorial no site Reagir É bem escrito, e abrange todos os fundamentos de uma forma que realmente explica como fazer. coisas). "Corretamente" aqui significa que você está escrevendo uma interface de aplicativo que é renderizada em um navegador; todo o trabalho da interface acontece no React, não no "com o qual você está acostumado se estiver escrevendo uma página da web" (é por isso que os aplicativos do React são "aplicativos", não "páginas da web").

Os aplicativos de reação são renderizados com base em duas coisas:

  1. as propriedades do componente, conforme declaradas por qualquer pai, cria uma instância desse componente, que o pai pode modificar ao longo do seu ciclo de vida, e
  2. o próprio estado interno do componente, que pode ser modificado ao longo de seu próprio ciclo de vida.

O que você não está fazendo expressamente quando usa o React está gerando elementos HTML e depois os utiliza: quando você diz ao React para usar um <input>, por exemplo, você não está criando um elemento de entrada HTML, está dizendo ao React para criar um objeto de entrada React que é renderizado como um elemento de entrada HTML e cuja manipulação de eventos examina, mas não é controlada pelos eventos de entrada do elemento HTML.

Ao usar o React, o que você está fazendo é gerar elementos da interface do usuário do aplicativo que apresentam dados ao usuário (geralmente manipuláveis), com a interação do usuário alterando o estado do Componente, o que pode fazer com que o re-renderizador de parte da interface do aplicativo reflita o novo estado. Nesse modelo, o estado é sempre a autoridade final, não "qualquer biblioteca da interface do usuário usada para renderizá-lo", que na Web é o DOM do navegador. O DOM é quase uma reflexão tardia nesse modelo de programação: é apenas a estrutura específica da interface do usuário que o React está usando.

Portanto, no caso de um elemento de entrada, a lógica é:

  1. Você digita o elemento de entrada,
  2. nada acontece com o seu elemento de entrada ainda, o evento foi interceptado pelo React e eliminado imediatamente ,
  3. Reagir encaminha o evento para a função que você configurou para manipulação de eventos,
  4. essa função pode agendar uma atualização de estado,
  5. caso isso aconteça, o React executa essa atualização de estado (de forma assíncrona!) e acionará uma renderchamada após a atualização, mas somente se a atualização do estado alterou o estado.
  6. somente depois que essa renderização ocorrer, a interface do usuário mostrará que você "digitou uma letra".

Tudo isso acontece em questão de milissegundos, se não menos, então parece que você digitou o elemento de entrada da mesma maneira que costumava "apenas usar um elemento de entrada em uma página", mas não é absolutamente isso que aconteceu.

Então, com isso dito, sobre como obter valores de elementos no React:

Reagir 15 e abaixo, com ES5

Para fazer as coisas corretamente, seu componente possui um valor de estado, que é mostrado por meio de um campo de entrada, e podemos atualizá-lo fazendo com que esse elemento da interface do usuário envie eventos de mudança de volta para o 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
    });
  }
});

Portanto, dizemos Reagir a usar a updateInputValuefunção para lidar com a interação do usuário, uso setStatepara agendar a atualização de estado, eo fato de que rendertorneiras em this.state.inputValuemeios que, quando se renderiza novamente depois de atualizar o estado, o usuário verá o texto de atualização com base no que eles digitado.

adendo baseado em comentários

Dado que as entradas da interface do usuário representam valores de estado (considere o que acontece se um usuário fechar sua guia no meio do caminho e a guia for restaurada. Todos os valores preenchidos devem ser restaurados? Se sim, esse é o estado). Isso pode fazer você sentir que um formulário grande precisa de dezenas ou até cem formulários de entrada, mas o React é sobre como modelar sua interface do usuário de maneira sustentável: você não possui 100 campos de entrada independentes, possui grupos de entradas relacionadas e, portanto, captura cada agrupe em um componente e, em seguida, crie seu formulário "mestre" como uma coleção de grupos.

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

Isso também é muito mais fácil de manter do que um componente de formulário único gigante. Divida os grupos em Componentes com manutenção de estado, onde cada componente é responsável apenas pelo rastreamento de alguns campos de entrada por vez.

Você também pode achar que é "um aborrecimento" escrever todo esse código, mas isso é uma falsa economia: os desenvolvedores que não são você, incluindo o futuro, se beneficiam muito ao ver todas essas entradas conectadas explicitamente, porque facilita muito o rastreamento dos caminhos de código. No entanto, você sempre pode otimizar. Por exemplo, você pode escrever um vinculador 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']}/>
    });
  }
});

Obviamente, existem versões aprimoradas disso, então acesse https://npmjs.com e procure uma solução de vinculação de estado React que você mais goste. O código-fonte aberto é principalmente descobrir o que os outros já fizeram e usá-lo em vez de escrever tudo do zero.

Reagir 16 (e 15,5 transitório) e JS 'moderno'

A partir do React 16 (e iniciação suave com 15.5), a createClasschamada não é mais suportada e a sintaxe da classe precisa ser usada. Isso muda duas coisas: a sintaxe óbvia da classe, mas também a thisligação de contexto que createClasspode ser executada "de graça"; portanto, para garantir que as coisas continuem funcionando, verifique se você está usando a notação "seta gorda" para thispreservar funções anônimas em onWhatevermanipuladores, como o onChangeque usamos no código aqui:

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

Você também pode ter visto pessoas usarem bindno construtor para todas as suas funções de manipulação de eventos, assim:

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

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

Não faça isso.

Quase sempre que você está usando bind, o proverbial "você está fazendo errado" se aplica. Sua classe já define o protótipo do objeto e, portanto, já define o contexto da instância. Não coloque bindpor cima disso; use o encaminhamento normal de eventos em vez de duplicar todas as suas chamadas de função no construtor, porque essa duplicação aumenta sua superfície de bugs e torna muito mais difícil rastrear erros, pois o problema pode estar no seu construtor e não no local onde você chama o código. Além de sobrecarregar os outros com quem você (tem ou escolhe) trabalhar.

Sim, eu sei que os documentos de reação dizem que está tudo bem. Não é, não faça.

Reagir 16.8, usando componentes de função com ganchos

A partir do React 16.8, o componente de função (isto é, literalmente, apenas uma função que usa algum propsargumento pode ser usado como se fosse uma instância de uma classe de componente, sem nunca escrever uma classe) também pode receber um estado, através do uso de hooks .

Se você não precisar de código de classe completo, e uma função de instância única será necessária, agora você poderá usar o useStategancho para obter uma variável de estado única e sua função de atualização, que funciona aproximadamente da mesma forma que os exemplos acima, exceto sem a setStatechamada de função:

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, a distinção não oficial entre classes e componentes de função era "componentes de função não têm estado", então não podemos mais nos esconder por trás disso: a diferença entre componentes de função e componentes de classe pode ser encontrada espalhada por várias páginas muito bem - documentação de reação escrita (nenhuma explicação de atalho para uma interpretação conveniente para você!), que você deve ler para saber o que está fazendo e, assim, saber se você escolheu a melhor solução (o que isso significa para você) para se programar fora de um problema que você está tendo.

Mike 'Pomax' Kamermans
fonte
4
Eu li alguns artigos on-line que dizem que usar muito estado é uma má idéia. Em uma forma específica do meu aplicativo, tenho cerca de 100 campos de formulário. Definir uma função para salvar o estado parece uma maneira desnecessariamente árdua de fazer as coisas. Se eu puder usar onClick = {this.onSubmit.bind (this)}, esta parece ser uma boa maneira de obter o valor (se desejar, defina o estado dos componentes) - eu gostaria de receber alguns comentários sobre isso.
precisa saber é o seguinte
5
então escreva um código mais inteligente. as entradas de formulário são definitivamente o estado (considere o que acontece se um usuário fechar sua guia no meio do caminho e a guia for restaurada. Todos os valores preenchidos devem ser restaurados? sim? esse é o estado ); portanto, escreva um pouco do código de manutenção do estado. O Facebook também possui centenas de valores de forma, e sua solução para a loucura foi o React. Funciona muito bem. Uma maneira de tornar seu código um pouco mais fácil, ainda usando o estado, é usar a vinculação de estado bidirecional , novamente, explicada no site React. Vale a pena ler! =)
Mike 'Pomax' Kamermans
2
Observe também que "100 campos" é principalmente irrelevante: divida seu formulário, porque não são 100 elementos, são várias seções, cada uma com várias entradas, portanto aplique um bom design e faça de cada seção seu próprio componente, com componentes de agrupamento para o formulário grupos. Isso normalmente torna um componente responsável por menos de 10 entradas e, de repente, sua arquitetura de informações faz muito mais sentido. O envio do formulário, como uma ação do navegador, é claro, apenas vê "o seu formulário" e envia tudo de uma só vez. Design de interface do usuário limpo e direcionado.
Mike 'Pomax' Kamermans
2
Obrigado pelos comentários. No entanto, notei que a vinculação de estado foi descontinuada a partir do React v15.
JoeTidee
3
@ JasonChing, você simplesmente criou bugs em potencial no seu código. Reagir não é um "ser tudo, acabar com todas as" solução para páginas da web, é uma estrutura para a construção de interfaces, e que é responsável pela gestão do estado e prestação UI real como reflexão tardia (os usuários não interagem com o DOM, eles interagem com Reagir: As atualizações do DOM são simplesmente um último passo assíncrono (mas incrivelmente rápido), para que a interface do usuário reflita visualmente o estado). Se você deseja ignorar isso, a pergunta mais importante é: por que você está usando o React? Porque o melhor sinal de que você está usando errado é combinar React e jQuery.
Mike 'Pomax' Kamermans
17

Conseguiu obter o valor do campo de entrada fazendo algo assim:

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
fonte
1
Por que usar "setState"? Isso envolve uma re-renderização ... não é?
Luca Davanzo 03/09/19
15

Em reagir 16, eu uso

<Input id="number" 
       type="time" 
       onChange={(evt) => { console.log(evt.target.value); }} />
Pyae Sone
fonte
não funciona se o campo foi preenchido automaticamente na carga idade
SeanMC
4

Consegui fazer isso vinculando o "this" à função updateInputValue (evt) com

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

No entanto, o valor de entrada = {this.state.inputValue} ... acabou não sendo uma boa ideia.

Aqui está o código completo no 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
fonte
2

seu erro é por causa de você usar classe e quando usar classe, precisamos vincular as funções com Isto para funcionar bem. de qualquer forma, há muitos tutoriais sobre por que devemos "isto" e o que é "isto" fazer em javascript.

se você corrigir o botão enviar, deve funcionar:

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

e também se você quiser mostrar o valor dessa entrada no console, use var title = this.title.value;

Soroush Bk
fonte
2
este link pode ser útil se você quiser saber mais sobre "isto"
Soroush Bk
2

<input>um ID único

<input id='title' ...>

e, em seguida, use a API da Web padrão para referenciá-la no DOM

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

Não há necessidade de atualizar continuamente o estado React a cada pressionamento de tecla. Basta obter o valor quando necessário.

Brent Washburne
fonte
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
fonte
Embora sua resposta possa ser boa para a pergunta, é sempre melhor adicionar algumas explicações. Reserve 2 minutos para adicioná-lo. Isso melhorará sua resposta também para usuários futuros.
DaFois
claro, eu farei isso.
Kidali Kevin
0

Você pode obter um valor de entrada sem adicionar a função 'onChange'.

Basta adicionar ao elemento de entrada um 'ref attr:

E use this.refs para obter o valor de entrada quando você precisar.

E1ad
fonte
3
Isso não é mais recomendado.
precisa saber é o seguinte
1
Você pode usá-los, mas é recomendável manter o fluxo de dados em uma direção usando adereços e retornos de chamada.
precisa saber é o seguinte
Seria bom adicionar um exemplo de adição de refs corretamente, ou seja, usando um retorno de chamada ref em vez de uma sequência herdada.
JoeTidee
0

Mude sua referência para: ref='title'e delete name='title' Então delete var title = this.titlee escreva:

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

Você também deve adicionar .bind(this)athis.onSubmit

(Funcionou no meu caso, que era bastante semelhante, mas em vez de o onClickfiz onSubmit={...}e foi colocado em forma ( <form onSubmit={...} ></form>))

Katarzyna Wrońska
fonte
0

se você usar o componente de classe, apenas três etapas - primeiro você precisará declarar o estado da sua entrada arquivada, por exemplo, this.state = {name: ''} . Em segundo lugar, você precisa escrever uma função para definir o estado quando ele muda no exemplo a seguir, é setName () e, finalmente, você deve escrever a entrada jsx, por exemplo, <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
senhor
fonte
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
fonte
0

usando campos não 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
fonte