Jaspal Hayer
Jaspal Hayer

Reputation: 67

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>
        );
    }
}

Upvotes: 1

Views: 3324

Answers (4)

SwinBlackSea
SwinBlackSea

Reputation: 11

 constructor(props) {
    super(props);
    ...
    resourceRemarks.forEach(x => {
        let resourceRemarkSwitch = "resourceRemarkSwitch" + x.index
        this.state = {
            ...this.state, [resourceRemarkSwitch]: true
        }
    })
}

Upvotes: 0

marco.marinangeli
marco.marinangeli

Reputation: 901

this.setState({
    book: {...this.state.book, title: e.target.value}
})

Upvotes: 4

Conan
Conan

Reputation: 690

you're changing the whole object, not just the value.

this.setState({
    book: {title: e.target.value}
});

changes the book state to your object, which only contains a title. Also, your constructor shouldn't be calling setState. it should be this.state = {...};

you might want to rethink how your component is set up, for example, if this book object comprises your entire state, you can just do:

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.State({
          title: '',
          author: '',
          year: '',
          isbn: '',
          price: '',
          desc: ''
    })

}

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

handleTitleTextFieldChange(e) {
    this.setState({
        title: e.target.value
    });
}

Upvotes: 3

TimoStaudinger
TimoStaudinger

Reputation: 42460

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
    })
});

Upvotes: 3

Related Questions