简体   繁体   中英

Rerender Component upon state change in React

I have an app which calls two functions; MyCart and MyItems. I am trying to make it so when the button rendered in MyItems is called it calls a method inside the main app component (the parent) and changes the state but for some reason, it doesn't change the value in the MyCart span.

My code below is what I am trying to do but it's not working and I can't figure out why.

class ShopRemake extends React.Component {
    constructor() {
        super();
        this.state = {
            total: 0
        }

        this.changeTotal = this.changeTotal.bind(this);
    }

    changeTotal() {
        this.setState(prevState => {total: ++prevState.total});
        console.log(this.state);
    }

    render() {
        return (
            <React.Fragment>
                <MyItem changeTotal={this.changeTotal}/>
                <MyCart total={this.state.total}/>
            </React.Fragment>
        );
    }
}

function MyItem(props) {
    return (
        <button onClick={props.changeTotal}> Click Me </button>
    );
}

function MyCart(props) {
    return (
        <span> Total Items: {props.total} </span>
    );
}

I want it so that after I click the button the span inside the MyCart to update accordingly.

You must wrap the returning object literal into parentheses in your arrow functions. Otherwise curly braces will be considered to denote the function's body. The following works:

p => ({ foo: 'bar' })

So the call to setState in changeTotal :

changeTotal() {
    this.setState(prevState => {total: ++prevState.total});
    console.log(this.state);
}

Should be replaced by the following :

changeTotal() {
    this.setState(prevState => ({total: ++prevState.total}));
    console.log(this.state);
}

Also, setState is asynchronous, you will need to either await it(not recommended) or use the callback as the second parameter to see the resulting state :

changeTotal() {
    this.setState(
        prevState => ({total: ++prevState.total}),
        () => { console.log(this.state) }
    );
}

EDIT :

Sidenote, the 2 components below in your code can be reduced into arrow functions for the exact same result, while making them easier to read :

const MyItem = ({ changeTotal }) => <button onClick={changeTotal}> Click Me </button>

const MyCart = ({ total }) => <span> Total Items: {total} </span>

And you can also convert changeTotal to an arrow function to avoid having to bind it in your constructor

Your setState is not returning an object here. Try to change your method changeTotal to this

changeTotal() {
     this.setState(prevState => ({ total: prevState.total + 1 }), () => 
     console.log(this.state));
}

The setState methods is asynchronous, if you want to log it's value, do this with a callback.

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