Reputation: 190
How come after I post something, the input fields' values remain the same, even after I change the state of data to null? I console.logged the state and after a post the data state variable is correctly set to an empty object, but the state of the inputs don't change. Please advise.
var AccountView = React.createClass({
getDefaultProps: function() {
return {
data: {},
users: [],
};
},
getInitialState: function() {
return {
data: {},
users: {},
};
},
componentDidMount: function() {
$.ajax({
url: "/react-webpack/js/source/controllers/get_accounts.php",
async: "false",
dataType: "json",
sucess: function(json) {
console.log("success!");
console.log(json);
},
error:function(x, e) {
alert(e);
},
complete: function(a, data) {
var users = JSON.parse(a.responseText);
this.setState({
users: users,
});
}.bind(this)
});
},
handleChange: function(e) {
var data = this.state.data;
data[e.target.name] = e.target.value;
this.setState({
data: data,
});
},
handleSave: function(e) {
e.preventDefault();
var users = this.state.users;
users.push(this.state.data);
$.ajax({
url: "/react-webpack/js/source/controllers/post_accounts.php",
type: "post",
data: this.state.data,
success: function(data, a) {
this.setState({
data: {},
});
}.bind(this),
error: function(e) {
},
complete: function(a, data) {
this.setState({
data: {},
users: users,
});
}.bind(this)
});
},
render: function() {
return (
<div className="container">
<form method="post">
<dl id="form" className="row">
<div className="col-md-4">
<dt>Firstname</dt>
<dd>
<input name="firstname" type="text" value={this.state.data.firstname} onChange={this.handleChange} />
</dd>
<dt>Lastname</dt>
<dd>
<input name="lastname" type="text" value={this.state.data.lastname} onChange={this.handleChange} />
</dd>
<dt>Password</dt>
<dd>
<input name="password" type="text" value={this.state.data.password} onChange={this.handleChange} />
</dd>
<dt>Email Address</dt>
<dd>
<input name="emailaddress" type="text" value={this.state.data.emailaddress} onChange={this.handleChange} />
</dd>
<dt>Submit</dt>
<dd>
<input type="submit" value="Submit" onClick={this.handleSave} />
</dd>
</div>
<div className="col-md-8">
<table>
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Password</th>
<th>Email address</th>
</tr>
</thead>
<tbody>
{_.map(this.state.users, function(user) {
return (
<tr>
<td>{user.firstname}</td>
<td>{user.lastname}</td>
<td>{user.password}</td>
<td>{user.emailaddress}</td>
</tr>
);
})}
</tbody>
</table>
</div>
</dl>
</form>
</div>
);
}
});
module.exports = AccountView;
Upvotes: 1
Views: 455
Reputation: 190
This is what I found to work based off of James Ganong's work, although note in my work environment setting the state to clear isn't necessary where the problem: null object not clearing the inputs doesn't exist.
handleSave: function(e) {
e.preventDefault();
var users = this.state.users;
users.push(this.state.data);
$.ajax({
url: "/react-webpack/js/source/controllers/post_accounts.php",
type: "post",
data: this.state.data,
success: function(data, a) {
this.setState({
data: {},
});
}.bind(this),
error: function(e) {
},
complete: function(a, data) {
var clear = {
firstname: '',
lastname: '',
password: '',
emailaddress: '',
};
this.setState({
data: clear,
users: users,
});
}.bind(this)
});
},
Upvotes: 1
Reputation: 1171
When you use value={this.state.data.firstname}
on an input, if this.state.data.firstname
is null or undefined and there is already a value set on the input, it keeps it. So when you set data
to an empty object, everything is passing null/undefined to the inputs.
So, when you update your state, instead of setting data
to an empty object, reset all the values to an empty string. A good way to do this is to first create a new initialState var outside of your class with the full shape of the state and then use it in your getInitialState
method:
var initialState = {
data: {
firstname: '',
lastname: '',
password: '',
emailaddress: ''
},
users: [] // also not this should be an array instead of an object
};
Inside your class:
getInitialState: function() {
// we're cloning initialState so it doesn't get modified directly
// as we want to use it later to reset the state
return Object.assign({}, initialState);
},
Next, instead of doing this.setState({ data: {} })
do this:
this.setState({
data: Object.assign({}, initialState.data)
});
On a side note, you also have two places where you're mutating the state directly - handleChange
and handleSave
:
handleChange: function(e) {
var data = this.state.data;
data[e.target.name] = e.target.value; // this is directly mutating the state
this.setState({
data: data,
});
},
// ...
handleSave: function(e) {
e.preventDefault();
var users = this.state.users;
users.push(this.state.data); // this is directly mutating the state
// ...
Mutating the state outside of setState()
can cause some weird unintended side effects and generally is a cause of poor performance.
To fix it, you first copy the state data, add to it, then set it (only requires simple changes):
handleChange: function(e) {
var data = Object.assign({}, this.state.data);
data[e.target.name] = e.target.value;
this.setState({
data: data,
});
},
// ...
handleSave: function(e) {
e.preventDefault();
var users = this.state.users.slice();
users.push(this.state.data);
// ...
Upvotes: 0