Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do setState inside callback: ReactJS

Following is the code that I used to set the state.

handleAddNewQuiz(event){
    this.quiz = new Quiz(this.db, this.newQuizName, function(err, affected, value){
        if(!err){
            this.setState( { quiz : value});  // ERROR: Cannot read property 'setState' of undefined
        }
    });
    event.preventDefault();
};

Rven though the database is created successfully, I cannot call this.state, as it's always undefined.

I tried:

self = this;

handleAddNewQuiz(event){
    this.quiz = new Quiz(this.db, this.newQuizName, function(err, affected, value){
        if(!err){
            self.setState( { quiz : value});  // ERROR: self.setState is not a function
        }
    });
    event.preventDefault();
};

But it still fails, tried with a = this, and use a.setState, still no luck.

How can I solve this?

like image 329
tonywei Avatar asked Apr 07 '17 10:04

tonywei


People also ask

How do you use setState callback in React?

setState Callback in a Class Component import React, { Component } from 'react'; class App extends Component { constructor(props) { super(props); this. state = { age: 0, }; } // this. checkAge is passed as the callback to setState updateAge = (value) => { this. setState({ age: value}, this.

Can you setState in a setState callback?

Yes, you can call setState() within the callback of another setState() .

Can we have a callback function which will be invoked when setState has finished?

The second argument that can optionally be passed to setState is a callback function which gets called immediately after the setState is completed and the components get re-rendered.

What happens when you call setState () inside render ()?

render() Calling setState() here makes it possible for a component to produce infinite loops. The render() function should be pure, meaning that it does not modify a component's state. It returns the same result each time it's invoked, and it does not directly interact with the browser.


2 Answers

You need to bind correct this (class context) with callback method, then only you will be able to access the class properties and methods.


Possible Solutions:

1- Use arrow function, like this:

 handleAddNewQuiz(event){
        this.quiz = new Quiz(this.db, this.newQuizName, (err, affected, value) => {
            if(!err){
                this.setState( { quiz : value}); 
            }
        });
        event.preventDefault();
    };

2- Or use .bind(this) with callback method, like this:

handleAddNewQuiz(event){
    this.quiz = new Quiz(this.db, this.newQuizName, function(err, affected, value){
        if(!err){
            this.setState( { quiz : value});  
        }
    }.bind(this));
    event.preventDefault();
};

The way you are using will also work, save the reference of this inside the handleAddNewQuiz method, like this way:

handleAddNewQuiz(event){
    let self = this;    //here save the reference of this
    this.quiz = new Quiz(this.db, this.newQuizName, function(err, affected, value){
        if(!err){
            self.setState( { quiz : value});  
        }
    });
    event.preventDefault();
};
like image 51
Mayank Shukla Avatar answered Sep 30 '22 15:09

Mayank Shukla


Mayank's answer is correct.. Alternatively you can use https://www.npmjs.com/package/core-decorators

and use the @autobind decorator before the function.

like image 43
JiN Avatar answered Sep 30 '22 16:09

JiN