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

我有以下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 -知道这段代码有什么问题吗?

755026 次浏览

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

首先要做的是:

理解React是如何工作的很重要,这样你才能正确地做事(提示:超级值得在React网站上运行React教程。它写得很好,并以一种实际解释如何做事的方式涵盖了所有的基础知识)。“Properly"这里的意思是你不是在写网页,你是在写一个恰好在浏览器中呈现的应用程序的用户界面;所有实际的用户界面工作都是在React中完成的,而不是在“你所习惯的写网页”中完成的。(这就是为什么React应用程序真正是“应用程序”,而不是“网页”)。

React应用程序的渲染基于两件事:

  1. 组件的属性是由创建该组件实例的父组件声明的,父组件可以在其整个生命周期中修改该实例
  2. 组件自己的内部状态,它可以在自己的生命周期中自我修改。

当你使用React时,你明确地所做的是生成HTML元素,然后使用这些:例如,当你告诉React使用<input>时,你不是在创建HTML输入元素,而是告诉React创建一个React输入对象,当你编译React应用程序的web时,该对象恰好呈现为HTML输入元素,事件处理由React控制。

当使用React时,你所做的是生成应用程序UI元素,向用户展示(通常是可操作的)数据,用户交互以定义的方式改变应用程序的状态——用户执行的操作可能会更新组件的道具或状态,React将其用作为更改的组件生成新的UI表示的信号,从而五月导致应用程序界面的部分更新以反映新状态。

在这个编程模型中,应用程序的内部状态是最终的权威,而不是“用户查看并与之交互的UI”:如果用户试图在输入字段中输入一些东西,而你没有编写任何东西来处理它,那么什么也不会发生:UI是应用程序状态的反映,而不是相反。实际上,浏览器DOM在这个编程模型中几乎是一个事后的想法:它恰好是一个超级方便的UI框架,整个星球几乎都可以访问(但它不是React唯一知道如何使用的框架)。

具体例子

了解了这些,让我们看看用户如何与React中的输入元素交互。首先,我们需要有一个UI元素供用户交互:

  1. 您编写了一个组件来管理(即存储和显示)用户的一些字符串数据,并使用onChange函数来处理用户数据。
  2. React使用组件的呈现代码生成一个包含input组件(而不是DOM <input>元素)的虚拟DOM,并将onChange处理程序绑定到该组件,以便可以使用React事件数据调用该组件(因此请注意,这不是DOM change事件侦听器,也不能获得与常规DOM事件侦听器相同的事件数据)。
  3. 然后React库将虚拟DOM转换为用户可以与之交互的UI,并且它将随着应用程序状态的变化而更新。因为它在浏览器中运行,所以它构建了一个HTML输入元素。

然后,你的用户尝试实际与输入元素交互:

  1. 用户单击输入元素并开始输入。
  2. 输入元素还没有发生任何变化。相反,输入事件会被React拦截并立即终止
  3. React将浏览器事件转换为React事件,并使用React事件数据为虚拟DOM组件调用onChange函数。
  4. 五月函数根据你写它的方式做一些事情,在这种情况下,你几乎可以肯定地写它来更新组件的状态,使用用户(尝试)键入的类型。
  5. 如果一个状态更新被安排,React将在不久的将来运行该状态更新,这将在更新后触发一个渲染通道。
  6. 在呈现过程中,它会检查状态是否真的不同,如果是,它会生成一个临时的第二个虚拟DOM,将其与应用程序的虚拟DOM(一部分)进行比较,确定需要对应用程序的虚拟DOM执行哪些添加/更新/删除操作集,使其看起来与新的临时DOM相同,然后应用这些操作并再次丢弃临时虚拟DOM。
  7. 然后更新UI,使其反映虚拟DOM现在的样子。
  8. 在所有这些之后,我们最终在用户实际查看的页面上有一个更新的DOM,他们看到他们在输入元素中输入了什么。

因此,这与常规的浏览器模型完全不同:用户不是通过在文本框中输入第一个来更新UI数据,我们的代码读取“该文本框的当前值”;为了弄清楚状态是第二个, React已经知道状态是什么,并使用事件更新状态第一个,这导致UI更新第二个

重要的是要记住,所有这些都是有效地立即发生的,所以对你的用户来说,它看起来就像他们在输入元素中输入文本一样,他们会以同样的方式输入任何随机的网页,但在底层,事情不能更不同,同时仍然导致相同的结果。

所以,有了这些,让我们看看如何从React中的元素中获取值:

组件类和ES6 (React 16+和15.5过渡)

从React 16开始(从15.5开始软启动),createClass调用不再受支持,需要使用类语法。这改变了两件事:明显的类语法,还有createClass可以做的thiscontext绑定"for free"所以为了确保事情仍然有效,请确保您使用"胖箭头"onWhatever处理程序中this上下文保留匿名函数的符号,例如我们在这里的代码中使用的onChange:

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.reset();
}


reset() {
// Always set the initial state in its own function, so that
// you can trivially reset your components at any point.
this.state = {
inputValue: ''
};
}


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


updateInputValue(evt) {
const val = evt.target.value;
// ...
this.setState({
inputValue: val
});
}
});

你可能也看到人们在构造函数中使用bind来处理所有的事件处理函数,像这样:

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


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

不要那样做。

几乎任何时候你在使用bind,俗话说“你做错了”;适用。您的类已经定义了对象原型,因此已经定义了实例上下文。不要把bind放在上面;使用正常的事件转发,而不是在构造函数中复制所有函数调用,因为这种复制增加了错误表面,并使跟踪错误变得更加困难,因为问题可能在构造函数中,而不是在调用代码的地方。

“但它又不断地在回放器上创造和抛弃功能!”这可能是真的,但你不会注意到。你的用户也不是。如果事件处理程序垃圾收集是你的性能瓶颈,那么你已经出了很多问题,你需要停下来重新思考你的设计:React工作得如此出色的原因是因为它不更新整个UI,它只更新发生变化的部分,在一个设计良好的UI中,大部分UI不发生变化的时间远远超过UI小部分更新的时间。

带有钩子的功能组件(React 16.8+)

从React 16.8开始,函数组件(即字面上只是一个接受一些props作为参数的函数,可以像使用组件类的实例一样使用,而无需编写类)也可以通过使用钩子来给定状态。

如果你不需要完整的类代码,一个实例函数就可以了,那么你现在可以使用useState钩子来获得一个状态变量,以及它的更新函数,其工作原理与上面的例子大致相同,只是没有"universal"setState函数调用,并为你正在处理的每个值使用一个专用的状态setter:

import { useId, useState } from 'react';


function myFunctionalComponentFunction(props) {
const id = useId();
const [input, setInput] = useState(props?.value ?? '');
return (
<div>
<label htmlFor={id}>Please specify:</label>
<input id={id} value={input} onInput={e => setInput(e.target.value)}/>
</div>
);
}

以前,类和功能组件之间的非官方区别是“功能组件没有状态”,所以我们不能再躲在这个后面了:函数组件和类组件之间的区别可以在写得很好的反应的文档中找到几页(没有简单的一行解释可以方便地为你误解!),你应该阅读它,这样你就知道你在做什么,从而知道你是否选择了最好的(无论这对你意味着什么)解决方案来编程自己摆脱你遇到的问题。

React 15及以下,使用遗留ES5和createClass

为了正确地做事情,你的组件有一个状态值,它通过输入字段显示,我们可以通过让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
});
}
});

因此,我们告诉React使用updateInputValue函数来处理用户交互,使用setState来安排状态更新,而render插入this.state.inputValue的事实意味着,当它在更新状态后重新呈现时,用户将看到基于他们键入的更新文本。

基于评论的增编

假设UI输入表示状态值(考虑一下如果用户中途关闭选项卡,选项卡会恢复会发生什么。他们填写的所有值都应该恢复吗?如果是,那就是状态)。这可能会让你觉得一个大表单需要几十个甚至100个输入表单,但React是关于以可维护的方式建模你的UI:你没有100个独立的输入字段,你有一组相关的输入,所以你在一个组件中捕获每一组,然后建立你的“;master"作为组的集合形成。

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

你的错误是因为你使用类,当使用类时,我们需要绑定函数与此,以便工作得很好。不管怎么说,有很多教程告诉我们为什么要用“this”,以及“this”在javascript中是做什么的。

如果你修正了提交按钮,它应该是工作的:

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

如果你想在控制台显示输入值你应该使用var title = this。title。value;

我通过将this绑定到函数成功地做到了这一点 updateInputValue(evt) < / p >

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

然而输入value={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;
}
}

你可以在不添加“onChange”函数的情况下获得输入值。

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

然后用这个。引用以在需要时获取输入值。

在react 16中,我使用

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

通过这样做来获得输入字段值:

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

你应该在MyComponent extends React类下使用构造函数。组件

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

然后你会得到标题的结果

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


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

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

此外,你还应该在this.onSubmit中添加.bind(this)

(它在我的情况下工作,这是非常相似的,但不是onClick,我有onSubmit={...},它被放在形式(<form onSubmit={...} ></form>))

如果你使用类组件,那么只需要3步——首先你需要声明输入字段的状态,例如这一点。State = {name: "}。其次,你需要写一个函数来设置状态,当它在下面的例子中改变时,它是setName (),最后你必须写输入jsx,例如& lt;input value={this.name} onChange ={this.setName}/> . input value={this.name

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


};

<input>一个唯一的id

<input id='title' ...>

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

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

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

使用不受控字段:

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}/>
...
</form>
...
<button type="button" className="btn">Save</button>
...
);
}


};

最简单的方法是使用箭头功能

箭头函数的代码

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

};

export default class App extends React.Component{
state={
value:'',
show:''
}


handleChange=(e)=>{
this.setState({value:e.target.value})
}


submit=()=>{
this.setState({show:this.state.value})
}


render(){
return(
<>
<form onSubmit={this.submit}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<input type="submit" />
</form>
<h2>{this.state.show}</h2>
</>
)
}
}

在功能组件中:- < / >强

export default function App(){


const [state, setState] = useState({
value:'',
show:''
});


const handleChange = (e) => {
setState({value: e.target.value})
}


const submit = () => {
setState({show: state.value})
}


return(
<>
<form onSubmit={()=>submit()}>
<input type="text" value={state.value} onChange={(e)=>handleChange(e)} />
<input type="submit" />
</form>
<h2>{state.show}</h2>
</>
)}

功能组件

useState

返回一个有状态值和一个更新它的函数。 在初始呈现期间,返回的状态(state)与作为第一个参数传递的值(initialState)相同。 setState函数用于更新状态。它接受一个新的状态值,并对组件的重新呈现进行排队。< br > src——比;https://reactjs.org/docs/hooks-reference.html#usestate < / p >

useRef

useRef返回一个可变的ref对象,其.current属性初始化为传递的参数(initialValue)。返回的对象将在组件的整个生命周期内持续存在。< br > src——比;https://reactjs.org/docs/hooks-reference.html#useref < / p >

import { useRef, useState } from "react";


export default function App() {
const [val, setVal] = useState('');
const inputRef = useRef();


const submitHandler = (e) => {
e.preventDefault();


setVal(inputRef.current.value);
}


return (
<div className="App">
<form onSubmit={submitHandler}>
<input ref={inputRef} />
<button type="submit">Submit</button>
</form>


<p>Submit Value: <b>{val}</b></p>
</div>
);
}
  • 反应版本:17.0.1

    a)使用功能组件

    b)使用hook: useState()管理状态。

编写并运行上面的代码:

import React, {useState} from 'react';


const InputElement = () => {
const [inputText, setInputText] = useState('');


return (
<div>
<input
onChange={(e) => {
setInputText(e.target.value);
}
}
placeholder='Enter Text'
/>
{inputText}
</div>
);
}

求解方案算法类似于双向数据绑定:

输入& lt; =比;DATA_MODEL & lt; =比;Label_Text