如何让我的组件返回自己的序列化?

时间:2016-02-05 21:08:00

标签: javascript reactjs

我还在学习React和Javascript,感谢您的耐心等待。

我正在尝试序列化我的表单数据,以便将其发送到Ruby on Rails后端进行处理。我只是使用vanilla React而没有其他依赖,如Flux,Redux等。

好像我的孩子组件没有返回任何东西,我不太清楚为什么。

我试过了:

  • 通过使用refs来暴露价值(但是失败并且认为无论如何都不是一个好主意)
  • 在我的子组件中公开父方法以收集有关每个组件的信息(您将在我的jsfiddle中看到的内容)。
  • 通过onChange方法更新组件状态并尝试访问每个子组件的状态

我的JSFiddle:https://jsfiddle.net/morahood/0ptdpfu7/91/

我显然错过了React设计模式的关键元素。我离开轨道了吗?我怎样才能回到正轨?我希望最终能够以下列格式序列化表单数据

{
   "service_request" : {
      "services" : [
        {
          "service_item" : ["Oil Change", "New Windshield Wipers"],
          "customer" : "Troy",
          "manufacturer" : "Ford",
          "model" : "F150"
        },
        {
          "service_item" : ["Tire Rotation"],
          "customer" : "Dave",
          "manufacturer" : "Hyundai",
          "model" : "Genesis"
        }
      ]
    }
}

部件

var ServiceForm = React.createClass({
  render: function() {
    return (
      <form onSubmit={ this.handleFormSubmission }>
        { this.state.serviceItems.map(function(item) {
          return (item);
        })}
        <div className="btn btn-default btn-sm" onClick={ this.addServiceItem }>+ Append New Service Item</div>
        <button type="submit" className="btn btn-success btn-lg pull-right">Submit</button>
      </form>
    );
  },

  getInitialState: function() {
    return ({
      serviceItems: [<ServiceItem serializeServiceItem={ this.serializeServiceItem } />]
    });
  },

  handleFormSubmission: function() {
    console.log("form submitted!");
    alert("Serialized Form Data: " +  this.serializeFormData());
  },

  addServiceItem: function(event) {
    var serviceItems = this.state.serviceItems;
    serviceItems.push(<ServiceItem serializeServiceItem={ this.serializeServiceItem } />);

    this.setState({
      serviceItems: serviceItems
    });
  },

  serializeServiceItem: function() {
    var jsonData = {
      "service_item" : this.state.service_items,
      "customer" : this.state.customer,
      "manufacturer" : this.state.manufacturer,
      "model" : this.state.model
    }
    return (jsonData);    
  },

  serializeFormData: function() {
    return( this.state.serviceItems.map(function(item) {
      return (item.serializeServiceItem);
    }));
  }
});

var ServiceItem = React.createClass({
  render: function() {
    return (
      <div className="row">
        <div className="col-sm-3">
          <div className="form-group">
            <label>Service Item </label>
            <select multiple name="service_item" selected={ this.state.service_items } className="form-control">
              <option>Oil Change</option>
              <option>Tire Rotation</option>
              <option>New Wiper Blades</option>
            </select>
          </div>
        </div>

        <div className="col-sm-3">
          <div className="form-group">
            <label>Customer </label>
            <select name="customer" selected={ this.state.customer } className="form-control">
              <option>Troy</option>
              <option>Dave</option>
              <option>Brandon</option>
            </select>
          </div>
        </div>        

        <div className="col-sm-3">
          <div className="form-group">
            <label>Manufacturer </label>
            <div className="input-group">
               <input name="manufacturer" value={ this.state.manufacturer } onChange={ this.setManufacturer } type="text" className="form-control" />
            </div>
          </div>
        </div>


        <div className="col-sm-3">
          <div className="form-group">
            <label>Model </label>
            <div className="input-group">
               <input name="model" value={ this.state.model } onChange={ this.setModel } type="text" className="form-control" />
            </div>
          </div>
        </div>
      </div>
    );
  },

  getInitialState: function() {
    return({
      service_items: [],
      customer: "",
      manufacturer: "",
      model: ""
    });
  },

  setModel: function(event) {
    this.setState({ model: event.target.value });
  },

  setManufacturer: function(event) { 
    this.setState({ manufacturer: event.target.value });
  },

  setCustomer: function(event) {
    this.setState({ customer: event.target.selected });
  },

  setServiceItems: function(event) {
    this.setState({ service_items: event.target.selected });
  }
});

ReactDOM.render(
  <ServiceForm />,
  document.getElementById('container')
);

解决方案

https://jsfiddle.net/morahood/cp569zg6/19/

2 个答案:

答案 0 :(得分:1)

你&#34;可能&#34;在这里过分复杂的事情。 irb(main):001:0> Property.find(1) Property Load (2.2ms) SELECT "properties".* FROM "properties" WHERE "properties"."id" = $1 LIMIT 1 [["id", 1]] Property Load (2.2ms) SELECT "properties".* FROM "properties" WHERE "properties"."id" = $1 LIMIT 1 [["id", 1]] => #<Property id: 1, listing_status: "In Draft", my_property_reference: "My reference", floor_area: 350, land_area: 500, state: "New Development", city: "Sydney", area: "CBD", street: "123 fake st", price: 800000, floors: 2, property_type: "Apartment", property_age: nil, completion: 2016, bedrooms: 5, bathrooms: 2, under_cover_car_spaces: 3, car_spaces: nil, car_lock_up_garage: 1, additional_information: "Great location in a great area.", description: "great house great house great house great house gr...", created_at: "2016-02-04 03:44:54", updated_at: "2016-02-04 03:46:55", suburb: nil> irb(main):002:0> Image.all Image Load (1.8ms) SELECT "images".* FROM "images" Image Load (1.8ms) SELECT "images".* FROM "images" => #<ActiveRecord::Relation []> irb(main):003:0> Image => Image(id: integer, main: boolean, attachment: string, created_at: datetime, updated_at: datetime, property_id: integer) irb(main):004:0> 的DOM元素实际上可以视为所有内部<form>元素的数组。换句话说,如果你有:

<input>

您可以通过以下方式访问所有输入元素:

render: function() {
  return (
    <form ref="form">
      ...
    </form>
  );
}

这可能无法为您提供足够的灵活性。更好的解决方案可能是在组件实例中定义返回输入值的方法:

serialized = {}
for (var i in this.refs.form) {
  var input = this.refs.form[i];
  serialized[input.name] = input.value;
}

如果您需要多个服务项,那么您可能需要依靠var ServiceForm = React.createClass({ serializeFormData: function() { return { foo: this.refs.foo.serialize() }; }, render: function() { var foo = this.state.foo; return ( <ServiceItem data={foo} ref="foo" /> ); } }); var ServiceItem = React.createClass({ serialize: function() { return { model: this.refs.model.value, ... } }, render: function() { var model = this.props.data.model; return ( <input ref="model" value={model} ... /> ); } }); 来访问每个组件实例而不是this.props.children

this.refs

请注意,我在这里使用React.Children而不是简单地使用var ServiceContainer = React.createClass({ collectFormData: function() { return this.refs.form.serialize(); }, renderServiceItem: function(item, i) { return ( <ServiceItem data={item} key={i} /> ); }, render: function() { // Assuming you've moved all your state logic into this ServiceContainer var serviceItems = this.state.serviceItems; return ( <ServiceForm ref="form"> {serviceItems.map(this.renderServiceItem)} </ServiceForm> ); } }); var ServiceForm = React.createClass({ serialize: function() { return React.Children.map(this.props.children, function(item) { return item.serialize(); }); }, render: function() { return ( <div>{this.props.children}</div> ); } }); var ServiceItem = React.createClass({ serialize: function() { // You can still access your input elements through refs in here ... }, render: function() { ... } }); ,因为当只有一个孩子时,this.props.children不是一个数组(请参阅: https://facebook.github.io/react/tips/children-props-type.html)。

答案 1 :(得分:0)

您可以使用react.rb和reactive-record,它将为您提供开箱即用的所有功能。 http://reactrb.org