1

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

1
  • Check out my answer... it’s the right way to go... Commented Apr 29, 2018 at 17:45

4 Answers 4

4
this.setState({
    book: {...this.state.book, title: e.target.value}
})
Sign up to request clarification or add additional context in comments.

Comments

3

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

3

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

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.