0

Currently working on React Native (iOS), with react-native-sqlite-storage. getUserData function is called by a component (ProfileView) and then it just logs it. If I try to log the array which is returned it works, but if I try to log the zero element of that same array it says that it's undefined. I have omitted okCallback and errorCallback as they just console.log the message sent to them. I also tried using objects and not arrays in getUserData, but it would just return undefined.

Database worker:

export function getUserData() {
    var arr = [];
    db.executeSql('SELECT * from userData;', [], results => {
        let len = results.rows.length;
        for(let i = 0; i < len; i++) {
            arr.push(results.rows.item(i));
        }
    });
    return arr;
}

class ProfileView extends React.Component {
    constructor(props) {
        super(props);
        var test = getUserData();
        console.log('not working', test[0])
        console.log('working', test)

    }

ProfileView:

class ProfileView extends React.Component {
constructor(props) {
    super(props);
    var test = getUserData();
    console.log('not working', test[0])
    console.log('working', test)

}

render() {
    return (...);
}
}

Thanks in advance

daedsidog
  • 1,732
  • 2
  • 17
  • 36
Emanuele Sacco
  • 411
  • 5
  • 20
  • Does this answer your question: https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – Mark Dec 01 '18 at 19:59
  • So `console.log('working', test)` works, but `console.log('not working', test[0])` doesn't? – StudioTime Dec 01 '18 at 19:59
  • 1
    Your problem is time. You can not check the contents of a box that you are going to fill tomorrow. The same way that you can not check the content of an Array, that will be filled in (let's say) 20ms. – Thomas Dec 01 '18 at 20:12

1 Answers1

0

As @Thomas said, it's a matter of timing.

Your database call is asynchronous. You create an empty array. Then you are providing a callback function to db.executeSql. That callback function gets called whenever the database returns the data, and it will add the elements to the array.

But while that's happening, your event loop keeps going. In your case, you are returning the (empty) array and doing your console.logs.

To make this work reliably, you have to have a mechanism in your component to watch for the database call to complete, and when it does to use the data. Generally that's what the react component state is for.

So we create a state, then we pass a callback into our getUserData. When the database call completes, it will update our state, and the component will re-render.

export function getUserData(cb) {
  var arr = [];
  db.executeSql('SELECT * from userData;', [], results => {
    let len = results.rows.length;
    for (let i = 0; i < len; i++) {
      arr.push(results.rows.item(i));
    }
    if (cb) cb(arr);
  });
  return arr;
}

ProfileView:

class ProfileView extends React.Component {
  constructor(props) {
    super(props);
    this.state = { test: [] };
    var test = getUserData(x => this.setState({ test: x }));
  }

  render() {
    if(this.state.test.length) console.log('not working', this.state.test[0]);
    console.log('working', this.state.test);
    return (...);
  }
}
David784
  • 7,031
  • 2
  • 22
  • 29
  • Thanks for your answer, but the problem persists. I moved the getUserData call to componentWillMount and there it stores it in component's state, then if I call this.state it returns me the state with user's data, but if, let's say the data is stored in this.state.data which is an array, I do this.state.data[0] it returns undefined. – Emanuele Sacco Dec 05 '18 at 19:13