Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Practice For Reading Form Data in React

Tags:

reactjs

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

Previously I did this sort of thing with a 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 React I can't seem to find an easy way to do that. It seems my only options are to ...

NOTE: Apologies for the formatting: code blocks and lists don't play well together :-(

  1. Completely bypass React and use the 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>;

    }

    That works, and is simple, but it feels like I'm bypassing React and using JQuery when I should just be using React.

  2. Provide callbacks to every form control:

    handleFooClick: function(e) {

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

    },

    render: function() {

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

    }

    This appears to be the React/Flux way, but it feels like a crazy amount of unnecessary work. In my Backbone example I needed just one line per form control, but with this approach every last control I build has to have its own onChange handler (and I have to hook that handler up to every element as I render it).

    EDIT: One more disadvantage of this approach is that inside the callbacks this.props and this.state won't point to my form control's props/state (it will point to the input's props/state). This means that not only do I have to write a handler per input AND add that callback to every input as I render, but I also have to pass in my data object to every input!

  3. Use refs:

    handleSubmit: function(e) {

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

    },

    render: function() {

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

    }

    This seems like a more sane solution, as I only need to add a "ref" attribute to every form control, and then I can read the data as easily as I could in Backbone. However, all the React documentation suggests that using refs that way is wrong (all of the examples using refs involve sending signals to the controls, eg. "focus on this input", not on reading data out of the controls).

I feel like there must be a "React-ive" way to access my form data that isn't needlessly complex, but I'm not seeing it because I don't understand React well enough. If any React expert could explain what I'm missing I would greatly appreciate it.

like image 624
machineghost Avatar asked Oct 01 '15 00:10

machineghost


2 Answers

First, jQuery is an unnecessary dependency and it's not the cleanest option so let's rule it out.

Next, refs have issues with flexibility. See this answer for details. Let's rule refs out for all but the simplest cases.

That leaves option #2 - what Facebook calls controlled components. Controlled components are great because they cover all use cases (like validation on keyup). Although it's not much code, if you'd rather not add a simple change handler for each form element, you might use one change handler for all elements with the use of bind. Something like this:

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 an even cleaner way, see this answer.

like image 172
Rick Jolly Avatar answered Oct 21 '22 06:10

Rick Jolly


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

Described here: https://facebook.github.io/react/docs/two-way-binding-helpers.html

like image 1
Carl Groner Avatar answered Oct 21 '22 07:10

Carl Groner