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

Joe*_*dee 157 javascript 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>
            ...
        );
    }

};
Run Code Online (Sandbox Code Playgroud)

控制台正在给我undefined- 任何想法这个代码有什么问题?

Mik*_*ans 244

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

与ES5反应15及以下

根据React文档和教程,通过正确操作.您正在编写一个基于两件事呈现的UI:

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

做的是生成一个输入元素DOM节点,然后键入它.您正在生成必须显示可操作文本字符串的UI,并且操作会更改Component的状态,这可能会导致重新呈现.国家永远是最终的权威,而不是DOM.DOM是一个事后的想法,它只是您碰巧使用的特定UI框架.

因此,为了正确地执行操作,组件具有状态值,通过输入字段显示,我们可以通过使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
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

你键入输入元素,你的输入元素没有任何反应,事件被立即截获并终止,React触发<input>事件的函数.这个功能要求反应更新组件的状态,使其具有正确的值,然后再与再重新描绘与新的更新你的UI,所以只有那么做用户界面显示您键入一个字母.所有这些都在几毫秒内发生,所以看起来你正常输入的东西,但这绝对不是发生的事情.

基于评论的附录

UI输入表示状态值(考虑如果用户在中途关闭其选项卡会发生什么,并且选项卡已恢复.是否应该还原所有填充的值?如果是,那就是状态).这可能会让你觉得大型表单需要几十甚至一百个输入表单,但React是以可维护的方式建模你的UI:你没有100个独立的输入字段,你有相关的输入组,所以你捕获每个组件中的组,然后将"主"表单构建为组的集合.

MyForm:
  render:
    <PersonalData/>
    <AppPreferences/>
    <ThirdParty/>
     ...
Run Code Online (Sandbox Code Playgroud)

这比一个巨大的单一形式组件更容易维护.将组拆分为具有状态维护的组件,其中每个组件仅负责一次跟踪一些输入字段.

您可能也觉得写出所有代码是"麻烦",但这是一种虚假的拯救:开发者 - 不是你,包括未来的你,实际上从看到所有这些输入明确地连接中获益很大,因为它使代码路径更容易跟踪.但是,您始终可以进行优化.例如,您可以编写状态链接器

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']}/>
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

当然,还有改进的版本,所以点击https://npmjs.com并搜索你最喜欢的React状态链接解决方案.开源主要是关于找到其他人已经完成的事情,并使用它而不是自己从头开始编写所有内容.

反应16(和15.5过渡)和'现代'JS

从React 16开始(以15.5开始软启动),render不再支持该调用,并且需要使用类语法.这改变了两件事:明显的类语法,还有可以"免费"执行的updateInputValue上下文绑定setState,因此为了确保事情仍然有效,请确保renderthis.state.inputValue处理程序中使用"胖箭头"表示法来保留匿名函数,例如在createClass我们这里的代码中使用:

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
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

您可能还看到人们this在构造函数中使用它们的所有事件处理函数,如下所示:

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

render() {
  return (
    ...
    <element onclick={this.handler}/>
    ...
  );
}
Run Code Online (Sandbox Code Playgroud)

不要那样做.

几乎在你使用的任何时候createClass,众所周知的"你做错了"都适用.您的类已经定义了原型,使用普通事件转发而不是在构造函数中复制所有函数调用.现在,您已经增加了bug表面,并且更难以跟踪错误,因为问题可能出在构造函数中而不是您调用代码的位置.除了对您(拥有或选择)使用的其他人施加维护负担之外.

是的,我知道反应文档说没关系.不是,不要这样做.

React 16.8,使用带挂钩的功能组件

从React 16.8开始,函数组件(即字面上只是一个函数,this可以使用某些作为参数的函数,就好像它是一个组件类的实例,而不用编写一个类)也可以通过使用钩子来给定状态.

如果您不需要完整的类代码,并且单个实例函数可以执行,那么您现在可以使用onWhatever钩子来获取单个状态变量及其更新函数,其工作方式与上面的示例大致相同,除非没有该onChange函数调用:

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>
  );
}
Run Code Online (Sandbox Code Playgroud)

以前,类和函数组件之间的非官方参数是"函数组件没有状态",因此我们不能再隐藏在那个函数组件之后:函数组件和类组件之间的区别可以在很好的页面中找到- 写入反应文档(没有快捷方便的单行解释,以方便你误解!),你应该阅读这些内容,以便你知道自己在做什么,从而知道你是否选择了最好的(对你而言意味着什么)解决方案来自己编程出于你遇到的问题.

  • 所以写更聪明的代码.表单输入绝对是状态(考虑如果用户在中途关闭其选项卡会发生什么,并且选项卡已恢复.他们填写的所有这些值是否应该恢复?是吗?*是状态*),所以写一些状态维护代码.Facebook也有数百种形式的价值,他们对疯狂的解决方案是React.它真的很好*.在使用状态的同时使代码更容易一种方法的一种方法是使用[双向状态链接](https://facebook.github.io/react/docs/two-way-binding-helpers.html),再次,在React网站上解释.值得阅读!=) (5认同)
  • 我读过一些在线文章,说使用太多状态是一个坏主意.在我的应用程序的一个特定形式中,我有大约100个表单字段.定义一个保存状态的功能感觉就像一种不必要的艰苦的做事方式.如果我可以使用onClick = {this.onSubmit.bind(this)},这似乎是获取值的好方法(如果我想要,设置组件状态) - 我将不胜感激. (4认同)
  • @JasonChing然后你只是在你的代码中构建了潜在的错误.React不是一个"全部,最终全部"的网页解决方案,它是一个构建界面的框架,*它*负责状态管理和实际的UI呈现,因为事后的想法(你的用户不与DOM交互,他们与React交互.DOM更新只是一个异步(但非常快)的最后一步,以便UI在视觉上反映状态).如果你想绕过它,更重要的问题是:你为什么使用React?因为你使用它的最佳标志是组合React和jQuery. (3认同)
  • 还要注意"100个字段"大多不相关:分割你的表单,因为它不是100个元素,它是几个部分,每个部分都有许多输入,所以应用好的设计并使每个部分成为自己的组件,并为表单分组组.这通常会使一个组件负责少于10个输入,并且突然您的信息架构变得更有意义.表单提交,作为浏览器操作,当然只是看到"您的表单"并一次性提交所有内容.干净,有针对性的UI设计. (2认同)
  • 感谢您的评论.但我注意到,从React v15开始,状态链接已被弃用. (2认同)

小智 21

你应该在类 MyComponent extends React.Component 下使用构造函数

constructor(props){
    super(props);
    this.onSubmit = this.onSubmit.bind(this);
  }
Run Code Online (Sandbox Code Playgroud)

然后你会得到标题的结果


小智 15

在功能组件中

使用状态

返回一个有状态的值以及一个更新它的函数。在初始渲染期间,返回的状态(state)与作为第一个参数传递的值相同(initialState)。该setState函数用于更新状态。它接受新的状态值并将组件的重新渲染排入队列。
src ---> https://reactjs.org/docs/hooks-reference.html#usestate

使用引用

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

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>
  );
}
Run Code Online (Sandbox Code Playgroud)


小智 14

通过执行以下操作来管理以获取输入字段值:

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
Run Code Online (Sandbox Code Playgroud)

  • 为什么使用“setState”?这涉及到重新渲染......不是吗? (4认同)

Bre*_*rne 12

<input>一个唯一的id

<input id='title' ...>
Run Code Online (Sandbox Code Playgroud)

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

const title = document.getElementById('title').value
Run Code Online (Sandbox Code Playgroud)

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

  • 在 React 中这将是一个非常糟糕的做法 (9认同)
  • @DivinesLight 你能解释一下为什么吗? (3认同)

Pya*_*one 9

在反应16中,我使用

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

  • 如果该字段在年龄负载时自动填充,则不起作用 (2认同)

小智 7

在功能组件中:-

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>
        </>
)}
Run Code Online (Sandbox Code Playgroud)


小智 6

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

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;
   }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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>
        </>
        )
    }
}
Run Code Online (Sandbox Code Playgroud)