Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify component state after a promise resolve

I want to modify a component's state (react native) after a promise is resolved.

Here is my code:

    class Greeting extends Component{

    constructor(props){
        super(props);

        this.state = {text: 'Starting...'};

        var handler = new RequestHandler();
        handler.login('email','password')
        .then(function(resp){
            this.setState({text:resp});
        });
    }

    render(){
        return (
            <Text style={this.props.style}>
                Resp: {this.state.text}
            </Text>
        );
    }
}

But when the promise resolve, it throws the following error:

this.setState is not a function
TypeError: this.setState is not a function
    at http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:1510:6
    at tryCallOne (http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:25187:8)
    at http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:25273:9
    at JSTimersExecution.callbacks.(anonymous function) (http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:8848:13)
    at Object.callTimer (http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:8487:1)
    at Object.callImmediatesPass (http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:8586:19)
    at Object.callImmediates (http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:8601:25)
    at http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:7395:43
    at guard (http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:7288:1)
    at MessageQueue.__callImmediates (http://localhost:8081/index.android.bundle?platform=android&dev=true&hot=false&minify=false:7395:1)

How can I change the current Component state after a promise is resolved?

like image 494
leo7r Avatar asked Aug 25 '16 19:08

leo7r


People also ask

Why is it not recommended to update a component state directly?

So, when you mutate the state directly and call setState() with an empty object. The previous state will be polluted with your mutation. Due to which, the shallow compare and merge of two states will be disturbed or won't happen, because you'll have only one state now.

Can we update state in component did mount?

componentDidMount() invokes immediately after a component mounts. You can call setState() immediately in componentDidMount() and triggers an extra rendering, but this happens before the browser updates the screen, calling render() twice.

Can the state of a component be updated directly?

When you directly update the state, it does not change this. state immediately. Instead, it creates a pending state transition, and accessing it after calling this method will only return the present value. You will lose control of the state across all components.


2 Answers

The callback has a different context than the object you are working with. For this reason, this is not what you think it is.


To solve this, you can use an arrow function, which keeps the surrounding context:

constructor(props){
    super(props);

    this.state = {text: 'Starting...'};

    var handler = new RequestHandler();
    handler.login('email','password')
        .then(resp => this.setState({text:resp}));
}

Alternatively, set the function context manually using bind():

constructor(props){
    super(props);

    this.state = {text: 'Starting...'};

    var handler = new RequestHandler();
    handler.login('email','password')
        .then(function(resp){
            this.setState({text:resp});
        }.bind(this));
}
like image 196
TimoStaudinger Avatar answered Sep 21 '22 17:09

TimoStaudinger


It's better to use new syntax. more here https://babeljs.io/blog/2015/06/07/react-on-es6-plus

class Greeting extends Component{
    state = {
      text: 'Starting...',
    }

    componentDidMount() {
      var handler = new RequestHandler();
      handler.login('email','password')
        .then((text) => {
            this.setState({ text });
        })
    }

    render(){
        return (
            <Text style={this.props.style}>
                Resp: {this.state.text}
            </Text>
        );
    }
}
like image 36
stereodenis Avatar answered Sep 23 '22 17:09

stereodenis