Nina
Nina

Reputation: 509

React: Cannot read property 'setState' of undefined

I've got some data from Firebase Realtime Database and now I'm trying to add it to a variable. I'm sure that the querying works, because if I console.log(dataSnapshot) it logs the correct data (which is 001). However, when I'm trying to create a variable out of that number I get the following error: Cannot read property 'setState' of undefined and it doesn't return anything to the console.

Here's my code:

class Table extends Component {
  constructor(props) {
    super(props);
    this.state = { timestamps: [], user: auth().currentUser, serial: "" };
  }

  componentDidMount() {
    const uid = this.state.user.uid;
    console.log(uid);
    let serial = this.state.serial;
    const serialRef = db.ref(uid + "/serial");
    serialRef.once("value").then(function (dataSnapshot) {
      console.log(dataSnapshot.val());
      this.setState({ serial: dataSnapshot.val() }, () => {
        serial = this.state.serial;
        console.log(serial);
      });
    });

Here's the screenshot of my console

Thanks in advance!

Upvotes: 0

Views: 89

Answers (3)

Muhammad Asad
Muhammad Asad

Reputation: 312

you are not using arrow callback function, If you don't use arrow callback you have to bind you function. If you don't want to write bind statement use arrow function which will get the context of the class automatically.

serialRef.once("value").then((dataSnapshot) => {
      console.log(dataSnapshot.val());
      this.setState({ serial: dataSnapshot.val() }, () => {
        serial = this.state.serial;
        console.log(serial);
      });
    });

Upvotes: 1

Alok Takshak
Alok Takshak

Reputation: 280

the arrow function should retain your this context

serialRef.once("value").then((dataSnapshot) => {
     console.log(dataSnapshot.val());
     this.setState({ serial: dataSnapshot.val() }, () => {
       serial = this.state.serial;
       console.log(serial);
     });

Upvotes: 0

Rytmis
Rytmis

Reputation: 32067

Your problem is that the callback you pass to serialRef.once("value").then(...) does not have a "this" context set. If you change your code to this, it should work:

componentDidMount() {
    const uid = this.state.user.uid;
    console.log(uid);
    let serial = this.state.serial;
    const serialRef = db.ref(uid + "/serial");
    // grab a reference to the current "this" context
    const table = this;
    serialRef.once("value").then(function (dataSnapshot) {
      console.log(dataSnapshot.val());

      // invoke setState on the captured context
      table.setState({ serial: dataSnapshot.val() }, () => {
        serial = table.state.serial;
        console.log(serial);
      });
    });

Or you could use a lambda function, like you already do in the setState call:

componentDidMount() {
    const uid = this.state.user.uid;
    console.log(uid);
    let serial = this.state.serial;
    const serialRef = db.ref(uid + "/serial");
     // "Fat arrow" or "lambda" functions implicitly capture the current "this" context
    serialRef.once("value").then((dataSnapshot) => {
      console.log(dataSnapshot.val());
      this.setState({ serial: dataSnapshot.val() }, () => {
        serial = this.state.serial;
        console.log(serial);
      });
    });

Upvotes: 0

Related Questions