0

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!

1

3 Answers 3

1

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

Sign up to request clarification or add additional context in comments.

Comments

0

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

2 Comments

Thanks for your answer! This works now. However, if I want to console.log(serial) outside of that function it doesn't log anything. serialRef.once("value").then((dataSnapshot) => { console.log(dataSnapshot.val()); this.setState({ serial: dataSnapshot.val() }, () => { serial = this.state.serial; console.log(serial); }); }); console.log(this.state.serial); Do you have any suggestions about how I could use that variable further on in the code?
I assume you're referring to the last console.log in this comment? In that case, I'm pretty sure it's because both serialRef.once() and this.setState() are asynchronous in nature. Practically what this means is that the execution of your code reaches the last console.log() before the setState completes, so you're trying to log it before the value is set. If you want to ensure that the state is set before doing something, you should do it in the callback of setState, like in your original example.
0

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

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.