【问题标题】:Get form data in ReactJS在 ReactJS 中获取表单数据
【发布时间】:2014-06-19 02:14:26
【问题描述】:

我的render 函数中有一个简单的表单,如下所示:

render : function() {
      return (
        <form>
          <input type="text" name="email" placeholder="Email" />
          <input type="password" name="password" placeholder="Password" />
          <button type="button" onClick={this.handleLogin}>Login</button>
        </form>
      );
    },
handleLogin: function() {
   //How to access email and password here ?
}

我应该在我的handleLogin: function() { ... } 中写什么来访问EmailPassword 字段?

【问题讨论】:

  • 注意:您应该在表单上处理onSubmit,而不是单击按钮 - 这样您还将处理用户通过按 Enter 提交表单。
  • 当用户在表单的任何&lt;input type=text&gt; 中按 Enter 键时,将提交带有 &lt;button&gt;&lt;form&gt; 或带有 type=submit&lt;input&gt;。如果您依赖一个按钮的onClick,用户必须单击该按钮或将其聚焦并按 Enter/空格键。使用 onSubmit 将启用这两个用例。当表单不支持 Enter 提交时,他们会感到崩溃。
  • 浏览器原生检查必填字段的空值也有好处

标签: javascript html reactjs frontend


【解决方案1】:

有几种方法可以做到这一点:

1) 通过索引从表单元素数组中获取值

handleSubmit = (event) => {
  event.preventDefault();
  console.log(event.target[0].value)
}

2) 在html中使用name属性

handleSubmit = (event) => {
  event.preventDefault();
  console.log(event.target.elements.username.value) // from elements property
  console.log(event.target.username.value)          // or directly
}

<input type="text" name="username"/>

3) 使用引用

handleSubmit = (event) => {
  console.log(this.inputNode.value)
}

<input type="text" name="username" ref={node => (this.inputNode = node)}/>

完整示例

class NameForm extends React.Component {
  handleSubmit = (event) => {
    event.preventDefault()
    console.log(event.target[0].value)
    console.log(event.target.elements.username.value)
    console.log(event.target.username.value)
    console.log(this.inputNode.value)
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            name="username"
            ref={node => (this.inputNode = node)}
          />
        </label>
        <button type="submit">Submit</button>
      </form>
    )
  }
}

【讨论】:

  • 选项 2 对我不起作用。没有属性“元素”或“用户名”,即使我输入的名称是“用户名”
  • @Madacol 这可能是因为您有几个同名的输入
  • 选项 2 是最佳答案。如果您已经拥有 event 参数,则通过 getElementById 获取元素是多余的。
【解决方案2】:

使用输入上的change 事件来更新组件的状态并在handleLogin 中访问它:

handleEmailChange: function(e) {
   this.setState({email: e.target.value});
},
handlePasswordChange: function(e) {
   this.setState({password: e.target.value});
},
render : function() {
      return (
        <form>
          <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} />
          <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
          <button type="button" onClick={this.handleLogin}>Login</button>
        </form>);
},
handleLogin: function() {
    console.log("EMail: " + this.state.email);
    console.log("Password: " + this.state.password);
}

工作fiddle

另外,阅读文档,有一整节专门用于处理表单:Forms

以前您也可以使用 React 的双向数据绑定助手 mixin 来实现相同的目的,但现在它已被弃用,有利于设置值和更改处理程序(如上):

var ExampleForm = React.createClass({
  mixins: [React.addons.LinkedStateMixin],
  getInitialState: function() {
    return {email: '', password: ''};
  },
  handleLogin: function() {
    console.log("EMail: " + this.state.email);
    console.log("Password: " + this.state.password);
  },
  render: function() {
    return (
      <form>
        <input type="text" valueLink={this.linkState('email')} />
        <input type="password" valueLink={this.linkState('password')} />
        <button type="button" onClick={this.handleLogin}>Login</button>
      </form>
    );
  }
});

文档在这里:Two-way Binding Helpers

【讨论】:

  • 要正确模仿valueLink 的功能,您的第一个示例应该设置输入元素的value。没有它,在 React 术语中的值为"uncontrolled"&lt;input ... value={this.state.password}&gt;.
  • 你也可以在表单中使用 onSubmit 而不是在按钮中使用 onClick
  • 为什么要为表单的每个元素使用一个状态?其他人认为这是一个糟糕的模式吗?
  • 看起来 valueLink 已被弃用
  • 这不是一直把密码明文保存在客户端吗?这似乎不太适合密码字段。
【解决方案3】:

另一种方法是使用ref 属性并使用this.refs 引用值。这是一个简单的例子:

render: function() {
    return (<form onSubmit={this.submitForm}>
        <input ref="theInput" />
    </form>);
},
submitForm: function(e) {
    e.preventDefault();
    alert(React.findDOMNode(this.refs.theInput).value);
}

更多信息可以在 React 文档中找到: https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute

由于How do I use radio buttons in React? 中描述的许多原因,这种方法并不总是最好的,但在一些简单的情况下它确实提供了一种有用的替代方案。

【讨论】:

  • 这个解决方案是否真的更好并且在提问时不可用,或者它是一种“丑陋”的方式?
  • 其实你不需要 React.findDOMNode this.refs.theInput 已经是一个html节点
  • refs 已贬值,此答案不再成立。
【解决方案4】:

补充 Michael Schock 的回答:

class MyForm extends React.Component {
  constructor() {
    super();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    event.preventDefault();
    const data = new FormData(event.target);

    console.log(data.get('email')); // reference by form input's `name` tag

    fetch('/api/form-submit-url', {
      method: 'POST',
      body: data,
    });
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label htmlFor="username">Enter username</label>
        <input id="username" name="username" type="text" />

        <label htmlFor="email">Enter your email</label>
        <input id="email" name="email" type="email" />

        <label htmlFor="birthdate">Enter your birth date</label>
        <input id="birthdate" name="birthdate" type="text" />

        <button>Send data!</button>
      </form>
    );
  }
}

See this Medium article: How to Handle Forms with Just React

此方法仅在按下提交按钮时获取表单数据。更清洁的海事组织!

【讨论】:

  • 这也可以防止在连续状态变化时重新渲染表单!
【解决方案5】:

对于那些不想使用 ref 并使用 OnChange 事件重置状态的人,您可以使用简单的 OnSubmit 句柄并循环遍历 FormData 对象。

请注意,您不能直接访问formData.entries(),因为它是可迭代的,您必须对其进行循环。

这个例子使用了 React Hooks:

const LoginPage = () => {
  const handleSubmit = (event) => {
    const formData = new FormData(event.currentTarget);
    event.preventDefault();
    for (let [key, value] of formData.entries()) {
      console.log(key, value);
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" name="username" placeholder="Email" />
        <input type="password" name="password" placeholder="Password" />
        <button type="submit">Login</button>
      </form>
    </div>
  );
};

如果您使用的是 TypeScript:

export const LoginPage: React.FC<{}> = () => {
  const handleSubmit: React.FormEventHandler<HTMLFormElement> = (event) => {
    const formData = new FormData(event.currentTarget);
    event.preventDefault();
    for (let [key, value] of formData.entries()) {
      console.log(key, value);
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" name="username" placeholder="Email" />
        <input type="password" name="password" placeholder="Password" />
        <button type="submit">Login</button>
      </form>
    </div>
  );
};

【讨论】:

  • 很好的答案,但是你可以删除 var 否则完美的解决方案!
  • 谁能帮我用上面这段代码 sn-p 的打字稿变体?
  • new FormData(event.target) 给我{}
  • @tejasvi88 您需要调用 FormData 对象上的条目。并非所有 JS 对象都会在记录时显示其内容。
  • @Joseph 我的表单实际上没有名称属性。
【解决方案6】:

无需使用refs,使用event即可访问

function handleSubmit(e) {
    e.preventDefault()
    const {username, password } = e.target.elements
    console.log({username: username.value, password: password.value })
}

<form onSubmit={handleSubmit}>
   <input type="text" id="username"/>
   <input type="text" id="password"/>
   <input type="submit" value="Login" />
</form>

【讨论】:

  • 太好了,这就是我要找的东西,谢谢
  • 元素有什么作用?找不到有关 e.target.elements 的任何信息
  • 有什么办法可以避免 id 重复?
  • @tejasvi88 你可以检查我的方法来避免id
  • Great Sameera - 这很容易从 vanilla js 中理解。谢谢
【解决方案7】:

处理 refs 的简单方法:

class UserInfo extends React.Component {

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

  handleSubmit(e) {
    e.preventDefault();
    
    const formData = {};
    for (const field in this.refs) {
      formData[field] = this.refs[field].value;
    }
    console.log('-->', formData);
  }

  render() {
    return (
        <div>
          <form onSubmit={this.handleSubmit}>
            <input ref="phone" className="phone" type='tel' name="phone"/>
            <input ref="email" className="email" type='tel' name="email"/>
            <input type="submit" value="Submit"/>
          </form>
        </div>
    );
  }
}

export default UserInfo;

【讨论】:

  • 这种方法将来有一天会被弃用。 Refs 只能用于回调而不是字符串。更多详情:facebook.github.io/react/docs/refs-and-the-dom.html
  • 酷! :) 我喜欢使用Object.keys(),然后是map(),如下所示:Object.keys(this.refs).map(field =&gt; formData[field] = this.refs[field].value)
  • 是的,字符串引用已被弃用。现在更好的方法是使用 onChange 回调。如果你仍然想使用 refs,你可以使用这个同步税:&lt;input type="text" ref={(input) =&gt; { this.textInput = input; }} /&gt;
  • 我@E.Fortes,你能解释一下onChange回调方法吗?如果你愿意的话,非常感谢。请标记我,以便我知道您的答案。
  • 一种简单的方法是(抱歉代码格式化程序不起作用): class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } render() { return (
    ); } }
【解决方案8】:

您可以将按钮上的onClick 事件处理程序切换为表单上的onSubmit 处理程序:

render : function() {
      return (
        <form onSubmit={this.handleLogin}>
          <input type="text" name="email" placeholder="Email" />
          <input type="password" name="password" placeholder="Password" />
          <button type="submit">Login</button>
        </form>
      );
    },

然后您可以使用FormData 来解析表单(如果您愿意,还可以根据其条目构造一个 JSON 对象)。

handleLogin: function(e) {
   const formData = new FormData(e.target)
   const user = {}

   e.preventDefault()

   for (let entry of formData.entries()) {
       user[entry[0]] = entry[1]
   }

   // Do what you will with the user object here
}

【讨论】:

【解决方案9】:

如果您的所有输入/文本区域都有名称,那么您可以从 event.target 中过滤所有内容:

onSubmit(event){
  const fields = Array.prototype.slice.call(event.target)
      .filter(el => el.name)
      .reduce((form, el) => ({
        ...form,
        [el.name]: el.value,
      }), {})
}

完全不受控制的形式?没有 onChange 方法、值、defaultValue...

【讨论】:

    【解决方案10】:

    我会建议以下方法:

    import {Autobind} from 'es-decorators';
    
    export class Form extends Component {
    
        @Autobind
        handleChange(e) {
            this.setState({[e.target.name]: e.target.value});
        }
    
        @Autobind
        add(e) {
            e.preventDefault();
            this.collection.add(this.state);
            this.refs.form.reset();
        }
    
        shouldComponentUpdate() {
            return false;
        }
    
        render() {
            return (
                <form onSubmit={this.add} ref="form">
                    <input type="text" name="desination" onChange={this.handleChange}/>
                    <input type="date" name="startDate" onChange={this.handleChange}/>
                    <input type="date" name="endDate" onChange={this.handleChange}/>
                    <textarea name="description" onChange={this.handleChange}/>
                    <button type="submit">Add</button>
                </form>
            )
        }
    
    }
    

    【讨论】:

    • 如果不重新渲染组件,如何根据当前状态设置每个元素的值?例如“value={this.state.destination}”。如果你不重新渲染它,你也不能在表单上运行反应验证
    【解决方案11】:

    es6 destructing 的更清晰示例

    class Form extends Component {
        constructor(props) {
            super(props);
            this.state = {
                login: null,
                password: null,
                email: null
            }
        }
    
        onChange(e) {
            this.setState({
                [e.target.name]: e.target.value
            })
        }
    
        onSubmit(e) {
            e.preventDefault();
            let login = this.state.login;
            let password = this.state.password;
            // etc
        }
    
        render() {
            return (
                <form onSubmit={this.onSubmit.bind(this)}>
                    <input type="text" name="login" onChange={this.onChange.bind(this)} />
                    <input type="password" name="password" onChange={this.onChange.bind(this)} />
                    <input type="email" name="email" onChange={this.onChange.bind(this)} />
                    <button type="submit">Sign Up</button>
                </form>
            );
        }
    }
    

    【讨论】:

      【解决方案12】:

      此外,这也可以使用。

      handleChange: function(state,e) {
        this.setState({[state]: e.target.value});
      },
      render : function() {
        return (
          <form>
            <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleChange.bind(this, 'email')} />
            <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handleChange.bind(this, 'password')}/>
            <button type="button" onClick={this.handleLogin}>Login</button>
          </form>
        );
      },
      handleLogin: function() {
        console.log("EMail: ", this.state.email);
        console.log("Password: ", this.state.password);
      }
      

      【讨论】:

      • 请解释为什么这个答案是正确的方法。
      • 我只使用一种方法来改变文本格式
      • react 开发工具里可以看到密码,是不是有点安全问题?
      【解决方案13】:

      像这样给你的输入参考

      <input type="text" name="email" placeholder="Email" ref="email" />
      <input type="password" name="password" placeholder="Password" ref="password" />
      

      然后你可以像 soo 一样在你的 handleLogin 中访问它

      handleLogin: function(e) {
         e.preventDefault();
          console.log(this.refs.email.value)
          console.log(this.refs.password.value)
      }
      

      【讨论】:

        【解决方案14】:

        如果你在你的项目中使用 Redux,你可以考虑使用这个高阶组件https://github.com/erikras/redux-form

        【讨论】:

          【解决方案15】:

          在 javascript 中的许多事件中,我们有 event 提供一个对象,包括发生了什么事件以及值是什么等...

          这也是我们在 ReactJs 中使用的表单...

          因此,在您的代码中,您将状态设置为新值……如下所示:

          class UserInfo extends React.Component {
          
            constructor(props) {
              super(props);
              this.handleLogin = this.handleLogin.bind(this);
            }
          
            handleLogin(e) {
              e.preventDefault();
              for (const field in this.refs) {
                this.setState({this.refs[field]: this.refs[field].value});
              }
            }
          
            render() {
              return (
                  <div>
                    <form onSubmit={this.handleLogin}>
                      <input ref="email" type="text" name="email" placeholder="Email" />
                      <input ref="password" type="password" name="password" placeholder="Password" />
                      <button type="button">Login</button>
                    </form>
                  </div>
              );
            }
          }
          
          export default UserInfo;
          

          这也是 React v.16 中的表单示例,作为您将来创建的表单的参考:

          class NameForm extends React.Component {
            constructor(props) {
              super(props);
              this.state = {value: ''};
          
              this.handleChange = this.handleChange.bind(this);
              this.handleSubmit = this.handleSubmit.bind(this);
            }
          
            handleChange(event) {
              this.setState({value: event.target.value});
            }
          
            handleSubmit(event) {
              alert('A name was submitted: ' + this.state.value);
              event.preventDefault();
            }
          
            render() {
              return (
                <form onSubmit={this.handleSubmit}>
                  <label>
                    Name:
                    <input type="text" value={this.state.value} onChange={this.handleChange} />
                  </label>
                  <input type="submit" value="Submit" />
                </form>
              );
            }
          }
          

          【讨论】:

            【解决方案16】:

            我是这样使用 React 组件状态的:

            <input type="text" name='value' value={this.state.value} onChange={(e) => this.handleChange(e)} />
            
            handleChange(e){
               this.setState({[e.target.name]: e.target.value})
            }`
            

            【讨论】:

              【解决方案17】:
               onChange(event){
                   console.log(event.target.value);
                }
                handleSubmit(event){ 
                  event.preventDefault();
                  const formData = {};
                    for (const data in this.refs) {
                      formData[data] = this.refs[data].value;
                    }
                  console.log(formData);
                }
              
              
              
               <form onSubmit={this.handleSubmit.bind(this)}>
                <input type="text" ref="username" onChange={this.onChange} className="form-control"/>
                <input type="text" ref="password" onChange={this.onChange} className="form-control"/>
                <button type="submit" className="btn-danger btn-sm">Search</button>
               </form>
              

              Output image attached here

              【讨论】:

              • 请提供解释。
              • 我会尝试解释这一点,我觉得这很棒。在 handleSubmit() 函数中,您正在构建一个对象 (formData),其中键是表单中每个输入的 'ref' 属性('formData[data]' 语句),值是输入的值使用这个 'ref' 属性('this.refs[data].value' 语句)。使用 'formData[data] = this.refs[data].value' 你正在构建这个对象。你说的字面意思是:formData['username'] =(用户名输入的值)和 formData['password'] =(密码输入的值)输出将是:{user: 'blablabla', password: 'xxx '}
              • 谢谢@SimonaAdriani 的解释。
              【解决方案18】:

              这是从表单获取数据的最短方法,也是避免使用 FormData 的 id 和 ref 的最佳方法

              import React, { Component } from 'react'
              
              class FormComponent extends Component {
                formSubmit = (event) => {
                  event.preventDefault()
                  var data = new FormData(event.target)
                  let formObject = Object.fromEntries(data.entries())
                  console.log(formObject)
                }
                render() {
                  return (
                    <div>
                      <form onSubmit={this.formSubmit}>
                        <label>Name</label>
                        <input name="name" placeholder="name" />
                        <label>Email</label>
                        <input type="email" name="email" />
                        <input type="submit" />
                      </form>
                    </div>
                  )
                }
              }
              export default FormComponent
              

              【讨论】:

                【解决方案19】:

                这可能有助于 Meteor (v1.3) 用户:

                render: function() {
                    return (
                        <form onSubmit={this.submitForm.bind(this)}>
                            <input type="text" ref="email" placeholder="Email" />
                            <input type="password" ref="password" placeholder="Password" />
                            <button type="submit">Login</button>
                        </form>
                    );
                },
                submitForm: function(e) {
                    e.preventDefault();
                    console.log( this.refs.email.value );
                    console.log( this.refs.password.value );
                }
                

                【讨论】:

                • this.submitForm.bind(this) 应该只是:this.submitForm
                • 错误:无状态函数组件不能有引用。
                • 你在使用 Meteor (v1.3) 吗?
                【解决方案20】:

                改善用户体验;当用户单击提交按钮时,您可以尝试让表单首先显示发送消息。一旦我们收到来自服务器的响应,它就可以相应地更新消息。我们通过链接状态在 React 中实现了这一点。请参阅下面的codepen 或 sn-ps:

                以下方法使第一次状态改变:

                handleSubmit(e) {
                    e.preventDefault();
                    this.setState({ message: 'Sending...' }, this.sendFormData);
                }
                

                只要 React 在屏幕上显示上述发送消息,它就会调用将表单数据发送到服务器的方法:this.sendFormData()。为简单起见,我添加了一个 setTimeout 来模仿这一点。

                sendFormData() {
                  var formData = {
                      Title: this.refs.Title.value,
                      Author: this.refs.Author.value,
                      Genre: this.refs.Genre.value,
                      YearReleased: this.refs.YearReleased.value};
                  setTimeout(() => { 
                    console.log(formData);
                    this.setState({ message: 'data sent!' });
                  }, 3000);
                }
                

                在 React 中,this.setState() 方法会渲染具有新属性的组件。因此,您还可以在表单组件的 render() 方法中添加一些逻辑,这些逻辑将根据我们从服务器获得的响应类型而有所不同。例如:

                render() {
                  if (this.state.responseType) {
                      var classString = 'alert alert-' + this.state.type;
                      var status = <div id="status" className={classString} ref="status">
                                     {this.state.message}
                                   </div>;
                  }
                return ( ...
                

                codepen

                【讨论】:

                  【解决方案21】:

                  如果一个元素名称多次出现,则必须使用 forEach()。

                  html

                    <input type="checkbox" name="delete" id="flizzit" />
                    <input type="checkbox" name="delete" id="floo" />
                    <input type="checkbox" name="delete" id="flum" />
                    <input type="submit" value="Save"  onClick={evt => saveAction(evt)}></input>
                  

                  js

                  const submitAction = (evt) => {
                    evt.preventDefault();
                    const dels = evt.target.parentElement.delete;
                    const deleted = [];
                    dels.forEach((d) => { if (d.checked) deleted.push(d.id); });
                    window.alert(deleted.length);
                  };
                  

                  注意这里的 dels 是 RadioNodeList,不是数组,也不是 Iterable。 forEach() 是列表类的内置方法。您将无法在此处使用 map() 或 reduce()。

                  【讨论】:

                    【解决方案22】:

                    这是一个动态添加字段的例子。此处表单数据将使用 React useState 钩子按输入名称键存储。

                    import React, { useState } from 'react'
                    
                    function AuthForm({ firebase }) {
                        const [formData, setFormData] = useState({});
                    
                        // On Form Submit
                        const onFormSubmit = (event) => {
                            event.preventDefault();
                            console.log('data', formData)
                            // Submit here
                        };
                    
                        // get Data
                        const getData = (key) => {
                            return formData.hasOwnProperty(key) ? formData[key] : '';
                        };
                    
                        // Set data
                        const setData = (key, value) => {
                            return setFormData({ ...formData, [key]: value });
                        };
                    
                        console.log('firebase', firebase)
                        return (
                            <div className="wpcwv-authPage">
                                <form onSubmit={onFormSubmit} className="wpcwv-authForm">
                                    <input name="name" type="text" className="wpcwv-input" placeholder="Your Name" value={getData('name')} onChange={(e) => setData('name', e.target.value)} />
                                    <input name="email" type="email" className="wpcwv-input" placeholder="Your Email" value={getData('email')} onChange={(e) => setData('email', e.target.value)} />
                                    <button type="submit" className="wpcwv-button wpcwv-buttonPrimary">Submit</button>
                                </form>
                            </div>
                        )
                    }
                    
                    export default AuthForm

                    【讨论】:

                      【解决方案23】:

                      我想这也是你需要的答案。另外,这里我添加了所需的属性。每个输入组件的 onChange 属性都是函数。您需要在此处添加自己的逻辑。

                      handleEmailChange: function(e) {
                          this.setState({email: e.target.value});
                      },
                      handlePasswordChange: function(e) {
                         this.setState({password: e.target.value});
                      },
                      formSubmit : async function(e) {
                          e.preventDefault();
                          // Form submit Logic
                        },
                      render : function() {
                            return (
                              <form onSubmit={(e) => this.formSubmit(e)}>
                                <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} required />
                                <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange} required />
                                <button type="button">Login</button>
                              </form>);
                      },
                      handleLogin: function() {
                          //Login Function
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2022-12-22
                        • 1970-01-01
                        • 2019-09-03
                        • 1970-01-01
                        • 2021-04-23
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多