Jaspal Hayer Jaspal Hayer - 21 days ago 13
React JSX Question

React overwriting state variables in an object

When I try to update a variable in an object in my state react seems to over-write the other variables in that object. I write to book.title, and then book.author but when I log book it only displays the last value I had written to it.

Thanks for any help in advance.

StepOne.js



class CreateListing extends Component {

constructor(props) {
super(props);
this.handleTitleTextFieldChange = this.handleTitleTextFieldChange.bind(this);
this.handleAuthorTextFieldChange = this.handleAuthorTextFieldChange.bind(this);
this.handleYearTextFieldChange = this.handleYearTextFieldChange.bind(this);
this.handlePriceTextFieldChange = this.handlePriceTextFieldChange.bind(this);
this.handleDescTextFieldChange = this.handleDescTextFieldChange.bind(this);
this.handleIsbnTextFieldChange = this.handleIsbnTextFieldChange.bind(this);
this.log = this.log.bind(this);

this.setState({
book: {
title: '',
author: '',
year: '',
isbn: '',
price: '',
desc: ''
}
})

}

log() {
console.log(this.state.book);
}

handleTitleTextFieldChange(e) {
this.setState({
book: {title: e.target.value}
});
}
handleAuthorTextFieldChange(e) {
this.setState({
book: {author: e.target.value}
});
}
handleYearTextFieldChange(e) {
this.setState({
book: {year: e.target.value}
});
}
handleIsbnTextFieldChange(e) {
this.setState({
book: {isbn: e.target.value}
});
}
handlePriceTextFieldChange(e) {
this.setState({
book: {price: e.target.value}
});
}
handleDescTextFieldChange(e) {
this.setState({
book: {desc: e.target.value}
});
}

render() {
return (
<div>
<h3 className="home-title">Create a listing</h3>
<h4 className="create-subtitle">Step 1 - Fill in the book details</h4>

<div className="create-title">
<div className="create-title-icon">
<i className="fa fa-book fa-1.8x"></i>
</div>
<TextField
hintText="What is the book title?"
style={style.textField}
multiLine={true}
onChange={this.handleTitleTextFieldChange}
/>
</div>


<div className="create-author">
<div className="create-author-icon">
<i className="fa fa-user fa-1.8x"></i>
</div>
<TextField
hintText="Who are the book authors?"
style={style.textField}
multiLine={true}
onChange={this.handleAuthorTextFieldChange}
/>
</div>

<div className="create-year">
<div className="create-year-icon">
<i className="fa fa-calendar fa-1.8x"></i>
</div>
<TextField
hintText="What year was the book published?"
style={style.textField}
multiLine={true}
onChange={this.handleYearTextFieldChange}
/>
</div>

<div className="create-isbn">
<div className="create-isbn-icon">
<i className="fa fa-barcode fa-1.8x"></i>
</div>
<TextField
hintText="What is the book ISBN?"
style={style.textField}
multiLine={true}
onChange={this.handleIsbnTextFieldChange}
/>
</div>

<div className="create-price">
<div className="create-price-icon">
<i className="fa fa-gbp fa-1.8x"></i>
</div>
<TextField
hintText="What is the desired price?"
style={style.textField}
multiLine={true}
onChange={this.handlePriceTextFieldChange}
/>
</div>

<div className="create-desc">
<div className="create-desc-icon">
<i className="fa fa-bookmark fa-1.8x"></i>
</div>
<TextField
hintText="Short description about the condition?"
style={style.textField}
multiLine={true}
onChange={this.handleDescTextFieldChange}
/>
</div>

<div className="create-next-button">
<RaisedButton
label="Next"
backgroundColor={Colors.pink500}
labelColor={Colors.white}
fullWidth={true}
onTouchTap={this.log}
style={style.button}/>
</div>
</div>
);
}
}




Answer

React's setState only does a shallow merge of the new and previous state, i.e. nested objects are completely replaced.

Instead, take care of the deep merge yourself:

this.setState({
    book: Object.assign({}, this.state.book, {
        title: e.target.value
    })
});
Comments