如何使用ReactJS获取输入字段的值?


188

我有以下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>
            ...
        );
    }

};

控制台给了我undefined-任何想法这段代码有什么问题吗?


7
this.onSubmit.bind(this);
zerkms 16-4-18的

尼斯-想要将其添加为答案,我将其勾选(?)
JoeTidee

2
怎么样e.target.value,而不绑定?
omarjmh

1
e.target.value是否将按钮而不是输入字段作为目标?
JoeTidee '16

onSubmit单击时,需要将方法绑定到提交按钮(DOM元素onClick={this.onSubmit.bind(this)})。而且,如果您想访问表单中标题输入的值,可以使用onSubmit(event) { const title = event.target.elements.title.value; }
tfmontague

Answers:


10

您应该在类MyComponent扩展React.Component下使用构造函数

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

然后您将获得标题的结果


313

这里有三个答案,这取决于您(被迫使用)React的版本,以及是否要使用挂钩。

第一件事:

理解React的工作原理很重要,这样您就可以正确地做事(提示:在React网站上运行React教程练习是非常值得的。它写得很好,并涵盖了所有基础知识,实际上是在解释如何做。东西)。这里的“正确”表示您正在编写一个恰好在浏览器中呈现的应用程序接口;所有界面工作都在React中进行,而不是在“编写网页时的习惯”中进行(这就是为什么React应用是“应用”而不是“网页”的原因)。

React应用程序基于以下两个方面进行呈现:

  1. 由任何父级创建的组件实例的实例声明的组件属性,父级可以在其整个生命周期中对其进行修改,并且
  2. 组件自身的内部状态,可以在其整个生命周期中对其进行修改。

当您使用React时,您显然没有做的是生成HTML元素,然后使用它们:<input>例如,当您告诉React使用一个时,您不是在创建HTML输入元素,而是在告诉React创建一个React输入对象它恰好呈现为HTML输入元素,并且其事件处理着眼于但不受 HTML元素的输入事件控制。

使用React时,您正在做的是生成应用程序UI元素,向用户展示(通常是可操作的)数据,并且用户交互会更改Component的状态,这可能导致应用程序界面的一部分重新呈现以反映新状态。在此模型中,状态始终是最终的权限,而不是“使用任何UI库呈现状态”,而状态权在网络上是浏览器的DOM。在这个编程模型中,DOM几乎是事后才想到的:它只是React恰好使用的特定UI框架。

因此,对于输入元素,逻辑为:

  1. 您输入输入元素,
  2. 您的输入元素没有任何反应,该事件被React拦截并立即终止
  3. React将事件转发到您为事件处理设置的功能,
  4. 该功能可以安排状态更新,
  5. 如果确实如此,React将运行状态更新(异步!),并render在更新后触发调用,但前提是状态更新更改了状态。
  6. 只有在进行此渲染之后,UI才会显示您“键入了字母”。

所有这些操作大约需要几毫秒,甚至更短的时间,因此看起来就像您从习惯于“仅在页面上使用输入元素”那样输入input元素一样,但这绝对不是发生了

因此,说到如何从React中的元素获取值:

使用ES5的React 15及以下版本

为了正确执行操作,您的组件具有状态值,该状态值通过输入字段显示,我们可以通过使UI元素将更改事件发送回该组件来对其进行更新:

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

所以我们告诉反应使用updateInputValue函数来处理用户交互,使用setState调度状态更新,而事实上,render接进this.state.inputValue的手段,当它更新状态后重新渲染,用户将看到基于他们键入的内容更新文本。

基于评论的附录

假设UI输入代表状态值(请考虑如果用户在中途关闭其选项卡并还原了选项卡,将会发生什么情况。是否应该还原他们填写的所有这些值?如果是,则为状态)。这可能会让您觉得大型表单需要数十个甚至一百个输入表单,但是React是关于以一种可维护的方式对UI建模:您没有100个独立的输入字段,有相关的输入组,因此您捕获了每个输入组合成一个组件,然后将“主”表单构建为一组组合。

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

这也比巨型单一表单组件容易维护。通过状态维护将组划分为组件,其中每个组件仅负责一次跟踪几个输入字段。

您可能还觉得写所有这些代码是“麻烦”的,但这是不正确的节省:看到您不知道的开发人员(包括将来的您)实际上会从看到所有这些输入明确挂钩中受益匪浅,因为它使代码路径更容易跟踪。但是,您始终可以进行优化。例如,您可以编写状态链接器

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

当然,对此有改进的版本,因此请访问https://npmjs.com并搜索您最喜欢的React状态链接解决方案。开源主要是寻找他人已经做过的事情,而不是从头开始编写所有内容。

React 16(和15.5过渡版)和``现代''JS

从React 16开始(以及从15.5开始软启动),createClass不再支持该调用,并且需要使用类语法。这将改变两件事:明显的类语法,this以及createClass可以“免费”执行的上下文绑定,因此要确保一切仍然正常,请确保使用“胖箭头”表示法thisonWhatever处理程序中保留上下文的匿名函数,例如在onChange这里的代码中,我们使用:

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

您可能还已经看到人们bind在其构造函数中使用了所有事件处理功能,如下所示:

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

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

不要那样做

几乎在您每次使用时bind,都会有一个谚语:“您做错了”。您的类已经定义了对象原型,因此已经定义了实例上下文。不要放在首位bind;请使用常规事件转发,而不是在构造函数中复制所有函数调用,因为这种复制会增加您的错误面,并且使跟踪错误变得更加困难,因为问题可能出在构造函数中而不是代码所在位置。以及给您(拥有或选择)与之共事的其他人增加维护负担。

是的,我知道react docs说很好。不是,不要这样做。

使用带钩子的功能组件进行React 16.8

从React 16.8开始,函数组件(即从字面上仅以某些props参数作为参数的函数就可以使用,就好像它是组件类的实例,而无需编写类)也可以通过使用hooks来获得状态。

如果您不需要完整的类代码,并且只需一个实例函数,则可以使用该useState钩子为自己获取一个状态变量及其更新函数,该函数的作用与上述示例大致相同,不同之处在于:该setState函数调用:

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

以前,类和功能组件之间的非正式区别是“功能组件没有状态”,因此我们再也无法躲藏起来:功能组件和类组件之间的区别可以很好地分布在几页上编写的反应文档(没有捷径说明可以方便地为您带来误解!),您应该阅读该文档,以便您知道自己在做什么,从而可以知道自己是否选择了最佳的(无论对您而言意味着什么)解决方案来进行编程摆脱您遇到的问题。


4
我读过一些在线文章,说使用过多状态是一个坏主意。在我的应用程序的一种特殊形式中,我有大约100个表单域。定义一个保存状态的功能感觉就像是一种不必要的繁琐的工作方式。如果我可以使用onClick = {this.onSubmit.bind(this)},这似乎是获取值的好方法(然后,如果需要,可以设置组件状态)-我希望对此发表一些评论。
JoeTidee '16

5
所以写更聪明的代码。表单输入绝对是状态(请考虑如果用户在中途关闭其选项卡并还原了选项卡,将会发生什么情况。是否应该还原他们填写的所有这些值?是的,这就是state),因此编写一些状态维护代码。Facebook也有成百上千的表单值,他们对这种疯狂的解决方案是React。它真的很好。在仍然使用状态的同时,使代码更容易一些的一种方法是再次使用两种方法进行状态链接,这在React网站上有所说明。值得读!=)
Mike'Pomax'Kamermans 16-4-18的

2
还要注意,“ 100个字段”基本上是无关紧要的:将表单拆分为100个元素,因为它不是100个元素,而是几个部分,每个部分都有大量输入,因此请应用良好的设计并使每个部分成为自己的组件,并对组件进行分组组。这通常使得组件负责少于10个输入,突然你的信息架构使得很多更有意义。表单提交作为浏览器动作,当然只会看到“您的表单”,并且一口气提交所有内容。干净,有针对性的UI设计。
Mike'Pomax'Kamermans

2
感谢您的评论。但是我确实注意到从React v15开始不赞成使用状态链接。
JoeTidee '16

3
@JasonChing,那么您只需在代码中内置潜在的错误。React不是网页的“一劳永逸”解决方案,它是一个用于构建界面的框架,负责状态管理和实际的UI渲染(事后考虑)(您的用户不与DOM交互,而是与DOM交互)。 DOM更新只是异步(但非常快)的最后一步,因此UI可以直观地反映状态。如果您想绕开它,更重要的问题是:为什么要使用React?因为您使用它的最好标志是将React和jQuery结合在一起。
Mike'Pomax'Kamermans

17

通过执行以下操作来设法获取输入字段的值:

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
为什么要使用“ setState”?这涉及到重新渲染。不是吗?
卡·达万佐

15

在反应16中,我使用

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

如果字段是根据年龄自动填充的,则无法正常工作
SeanMC '19

4

通过将“ this”绑定到函数updateInputValue(evt),我成功地做到了

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

但是,输入值= {this.state.inputValue} ...并不是一个好主意。

这是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

您的错误是因为您使用了类,并且在使用类时,我们需要使用This绑定函数才能正常工作。无论如何,有很多教程为什么我们应该在JavaScript中执行“ this”和“ this”是什么。

如果您更正了提交按钮,它应该可以工作:

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

并且如果您想在控制台中显示该输入的值,则应使用var title = this.title.value;。


2
如果您想了解更多有关“本”的信息,则此链接可能会有所帮助
Soroush Bk 2016年


2

给出<input>一个唯一的ID

<input id='title' ...>

然后使用标准的Web API在DOM中引用它

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

无需每次按键都不断更新React状态。只需在需要时获取值即可。


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" />

虽然您的答案可能对问题有帮助,但最好添加一些解释。请花2分钟将其添加。这也将为将来的用户改善您的答案。
DaFois

当然,我会这样做。
基达利·凯文

0

您无需添加“ onChange”功能就可以获取输入值。

只需在输入元素中添加一个'ref attr:

然后在需要时使用this.refs获取输入值。


3
不再建议这样做。
JoeTidee

1
您可以使用它们,但是建议使用props和callbacks保持数据流向一个方向。
JoeTidee

最好添加一个示例,以正确添加引用,即使用引用回调而不是旧式字符串。
JoeTidee

0

将您的引用更改为:ref='title'并删除name='title' 然后删除var title = this.title并写入:

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

您还应该添加.bind(this)this.onSubmit

(在我的情况下,它的工作原理非常相似,但是代替了onClickonSubmit={...},它以(<form onSubmit={...} ></form>))形式放置


0

如果使用类组件,则只需3个步骤-首先,您需要声明输入字段的状态,例如this.state = {name:''}。其次,在下面的示例中,您需要编写一个用于设置状态更改的函数,即setName(),最后必须编写输入jsx,例如 <输入值= {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

使用不受控制的字段:

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

};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.