简体   繁体   中英

React.js - Rails: Set State

I have two components: App and Registration Form

The form has two inputs: Name and Last name

Looking at the App state in dev. tools I see length: undefined and name: "name entered". I'm not getting any errors but I'm missing the last name.

This is only happening in Rails. I tried the same code in a non rails environment and it works fine. I'm using this gem for React: gem 'react-rails', '~> 1.5.0' and running Rails 4.2.4

var App = React.createClass({
    getInitialState : function(){
        return {
            registrations: {}
        }
    },
    addRegistration : function(registration){
        // create unique id 
        var timestamp = (new Date()).getTime();
        // update state 
        this.state.registrations['registration-' + timestamp] = registration;
        //set the state
        this.setState({ registrations : this.state.registrations });

    },
    render : function(){
        return (
            <RegistrationForm addRegistration={this.addRegistration}/>
        )
    }
});

var RegistrationForm = React.createClass({
    createRegistration : function(event){
        // prevent default
        event.preventDefault();
        // take data from form and create object
        var registration = {
            name : this.refs.name.value,
            lastname : this.refs.lastname.value
        }
        // Add registration to App Object
        this.props.addRegistration(registration);
        this.refs.registrationForm.reset();

    //console.log(registration);
    },
    render : function(){
        return (
            <div className="col-sm-12">
                <form action="" className="form" ref="registrationForm" onSubmit={this.createRegistration}>
                    <div className="form-group">
                        <label >Name</label>
                        <input className="form-control" ref="name"/>
                    </div>
                    <div className="form-group">
                        <label >Last Name</label>
                        <input className="form-control" ref="lastname"/>
                    </div>
                    <div>
                        <button className="btn btn-primary">Submit</button>
                    </div>
                </form>
            </div>
        )
    }
});

App = React.createFactory(App)

What I'm trying to do is to give each registration a unique id number based on the time stamp.

When I console log the following:

addRegistration : function(registration){
    // create unique id 
    var timestamp = (new Date()).getTime();
    // update state 
    this.state.registrations['registration-' + timestamp] = registration;
    //set the state
    this.setState({ registrations : this.state.registrations });

},

I can see a registration object the way I want it. I can add as many unique registrations to the App state but each registration has length: undefined, name: "name" , but it's missing the last name.

If I change the set state to this:

this.setState({ registrations : registration });

This gives me a single registration with name and last name but it doesn't add multiple registrations. It only creates one registration which gets update every time I submit the add registration form.

this.state.registrations['registration-' + timestamp] = registration;

You seem to be mutating the state directly, based on the React Docs https://facebook.github.io/react/docs/component-api.html

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate() . If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate() , calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.

Try cloning the current state then use that as the argument.

// if array
var clonedRegistration = this.state.registrations.slice();
clonedRegistration['registration-' + timestamp] = registration;

this.setState({registrations: clonedRegistration})

or

this.setState({registrations: {['registration-'+ timestamp]: registration} });

I think the answer Road put was close.

First set your initial state to an array.

getInitialState: function(){
      return { registrations: []}
    }

your addRegistration function

addRegistration : function(registration){

I think this is what you're missing:

//getting current state
var oldRegistrations = this.state.registrations;

Otherwise I believe you're updating the same thing over and over, instead of adding a new registration object. Then push your registration. You should set the timestamp

// update state 
oldRegistrations.push(registration);
var registrations = oldRegistrations;

//set the state

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

I would advise creating the id somewhere in here since you're not using an actual ajax call to a rails db:

var registration = {
            name : this.refs.name.value,
            lastname : this.refs.lastname.value
                  id: (new Date()).getTime();
}

I'm not sure I understand your question regarding your form values or if you were having trouble with them. But if you were I think doing something like this may help:

 <input type='text' className='form-control'
                 placeholder='Name' name='name'
                 value={this.state.name} onChange={this.handleChange} >
 </input>

 <input type='text' className='form-control'
                 placeholder='Last Name' name='last name'
                 value={this.state.last_name} onChange={this.handleChange} >
 </input>

Then implement a handleChange function within the same component to constantly handle the form's values onChange. That should look like this:

handleChange: function(e) {
    var name = e.target.name;
    var obj = {};
    obj[name] = e.target.value;
    this.setState(obj);
} 

Hope this helps,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM