Best practice for reading form data in action

I'm trying to do something in React, it would be very simple in any other framework: I want to collect a bunch of values ​​from the form.

I used to do similar things with Backbone View, and it was very simple:

readFormValues: function() { this.data.foo = this.$('[name="foo"]').val(); this.data.bar = this.$('[name="bar"]:checked').val(); }); 

But in Reactics, I cannot find an easy way to do this. It seems my only options ...

NOTE: Apologies for formatting: code blocks and lists do not work well: - (

  • e.target React completely and use jQuery + e.target to access the form:

    handleSubmit: function(e) {

    var $form = $(e.target).parents('form:first');

    this.data.foo = $form.find('[name="foo"]);

    },

    render: function() {

    return <form onSubmit="handleSubmit"><input name="foo"/></form>;

    }

    This works and is simple, but it seems to me that I circumvented React and used jQuery when I just had to use React.

  • Provide callbacks for each form control:

    handleFooClick: function(e) {

    this.data.foo = event.target.value;

    },

    render: function() {

    return <form><input name="foo" onChange="handleFooChange"/></form>;

    }

    This seems to be the React / Flux way, but it feels like an insane amount of unnecessary work. In my Backbone example, I needed only one line for the form control, but with this approach, every last control I built should have its own onChange handler (and I have to hook this handler before each element when I render it).

    EDIT: Another drawback of this approach is that inside the this.props and this.state will not point to my details / form control state (it will point to details / state). This means that I not only have to write a handler for each input and add this callback to each input, as I visualize, but I also need to pass my data object to each input!

  • Use links:

    handleSubmit: function(e) {

    this.state.data.foo = this.refs.foo.value;

    },

    render: function() {

    return <form><input ref="foo"/></form>;

    }

    This seems like a smarter solution, since I need to add a “ref” attribute for each form control, and then I can read the data as easily as I could in Backbone. However, all React documentation assumes that the use of references is incorrect (all examples using refs include sending signals to controls, such as “focus on this input” rather than reading data from the controls).

I feel that there must be a “Responsive” way to access my form data, which is not unnecessarily complicated, but I do not see it because I do not understand React enough. If any reagent expert could explain what I was missing, I would really appreciate it.

+7
reactjs
source share
5 answers

First of all, jQuery is an unnecessary dependency, and this is not the cleanest option, so let this rule out.

Further, refs have problems with flexibility. See more details. Let the rule refs for all but the simplest cases.

This leaves option # 2 - what Facebook calls controlled components . Controlled components are great because they cover all use cases (like checking on the keyboard). Although this is not a lot of code, if you do not want to add a simple change handler for each form element, you can use one change handler for all elements using bind . Something like that:

 handleChange: function(fieldName, e) { console.log("field name", fieldName); console.log("field value", e.target.value); // Set state or use external state. }, render: function() { var someValue = this.state.someValue; // Or a prop is using external state return ( <div> <input name="someName" value={someValue} onChange={this.handleChange.bind(this, "someName")} /> </div> ) } 

Or for a cleaner way, see this answer .

+2
source share

You can use ReactLink to create a two-way binding between your responsive component and your state.

Described here: https://facebook.imtqy.com/react/docs/two-way-binding-helpers.html

+1
source share

For a smaller project, I use one onChange call for all inputs - something like this ...

 HandleClick(event) { let values = this.state.values; values[event.target.name] = event.target.value; this.setState({values}); } 

This requires that you enter your inputs the same way you call their state property, but I really like it. Then you assign the value stored in the state to the value attribute of your input, and you are all set up - all your form state is stored in one place using one handler function.

Of course, there are more scalable ways - I just read about the structure for the reaction called formsy, which looked interesting. Here's a tutorial: http://christianalfoni.imtqy.com/javascript/2014/10/22/nailing-that-validation-with-reactjs.html

Hope that helps

Dan

+1
source share

This is how I handle all the fields in the form.

  var My_Field=React.createClass({ _onChange: function(evt) { var e=this.props.parent_form; if (e) { e.setState({email: evt.target.value}); } }, render: function() { return ( <input type="text" name={this.props.name} placeholder={this.props.label} onChange={this._onChange}/> ); } }); var My_Form=React.createClass({ getInitialState: function() { return { email: "", }; }, _onSubmit: function(evt) { evt.preventDefault(); alert(this.state.email); }, render: function() { return ( <form onSubmit={this._onSubmit}> <My_Field name="email" label="Email" parent_form={this}/> <input type="submit" value="Submit"/> </form> ); } }); 
+1
source share

You can read form data using only one function.

the SignUp class extends the {

 constructor(){ super(); this.handleLogin = this.handleLogin.bind(this); } handleLogin(e){ e.preventDefault(); const formData = {}; for(const field in this.refs){ formData[field] = this.refs[field].value; } console.log('-->', formData); } render(){ return ( <form onSubmit={this.handleLogin} className="form-horizontal"> <div className="form-group text-left"> <label className="control-label col-sm-2">Name:</label> <div className="col-sm-10"> <input ref="name" type="text" className="form-control" name="name" placeholder="Enter name" /> </div> </div> <div className="form-group text-left"> <label className="control-label col-sm-2">Email:</label> <div className="col-sm-10"> <input ref="email" type="email" className="form-control" name="email" placeholder="Enter email" /> </div> </div> <div className="form-group text-left"> <label className="control-label col-sm-2">Password:</label> <div className="col-sm-10"> <input ref="password" type="password" className="form-control" name="password" placeholder="Enter password" /> </div> </div> <div className="form-group text-left"> <div className="col-sm-offset-2 col-sm-10"> <button type="submit" className="btn btn-primary btn-block">Signup</button> </div> </div> </form> ) } }export default SignUp; 
0
source share

All Articles