React Native : Handling Async calls to sqllite db

4.7k views Asked by At

I am having a bit of struggle trying to understand how async functions work in React Native.

In this example I am invoking a sqllite db call via a async call and get values of height and standard and return both these values as an object called result.

Values exist in sqllite db as can be seen in the console output shown below.

The method invoked from componentDidMount lifecycle method is an async method.

As can be seen I am using await to wait for the actual execution (aka getting data from sqllite) to complete.

Line X always returns as undefined.

Line Y does not seem to execute at all as the state does not get changed from the initial values of 100 & "asasd" at all.

I have eyeballed the code and I am not sure what I am missing here.

Can someone take a look at it and let me know ?

App.js

import React, { Component } from 'react';
import { View, Text } from 'react-native';
import {
  dropLogsTable,
  createLogsTable,
  getProfileHeightStandardfromDB,
  getProfileHeightStandardPremade,
  saveLogsRecord
} from '../src/helper';

export default class App extends Component {
  state = {
    logarray: [],
    profileobject: {profileheight: 100, profilestandard: "asasd"},

  };


  componentDidMount() {

    dropLogsTable();
    createLogsTable();
    this.fetchProfileData();


  }

  async fetchProfileData() {
    console.log('Before Profile Fetch');
    const result = await getProfileHeightStandardfromDB();
    console.log('After Profile Fetch');
    console.log('Height : '+result.profileheight);
    console.log('Standard: '+result.profilestandard);
    return result; //Line X
    this.setState({profileobject:result}); //Line Y
  }

  render() {
    return (
      <View>
        <Text>This is a test</Text>
        <Text>Profile Height : {this.state.profileobject.profileheight} </Text>
        <Text>Profile Standard : {this.state.profileobject.profilestandard}</Text>
      </View>
    );
  }
}

helper.js

import { SQLite } from 'expo';

const db = SQLite.openDatabase({ name: 'swlt.db' });

let profileheight, profilestandard;

export function getProfileHeightStandardfromDB()
          {
        db.transaction(
          tx => {

            tx.executeSql('select standard, metricweight, metricheight, imperialheight, imperialweight, bmi, metricgoalweight, imperialgoalweight from profile', [], (_, { rows }) =>
              {
                //console.log(rows);
                console.log(rows);

                //console.log(parseFloat(rows._array[0].metricheight));
                profileheight = parseFloat(rows._array[0].metricheight);
                profilestandard = rows._array[0].standard;
                console.log('Profileheight ===>'+profileheight);
                console.log('Profilestandard ===>'+profilestandard);
              }
            );
          },
          null,
          null
        );

        const profileobject = {profileheight, profilestandard};
        console.log(profileobject);
        return profileobject;

      }

Output from Device and Console

enter image description here

enter image description here

2

There are 2 answers

0
Raghudevan Shankar On BEST ANSWER

You seem to have the this.setState after a return statement; no code after the return statement will execute. Just put the this.setState call before the return block

Also, the function getProfileHeightStandardfromDB() needs to be an async function or needs to return a Promise. Currently the method does not return a Promise so theres no point awaiting it. So heres what you would need to do

function getProfileHeightStandardfromDB() {
  return new Promise((resolve, reject) => {
    db.transaction(
      tx => {
        tx.executeSql('select standard, metricweight, metricheight, imperialheight, imperialweight, bmi, metricgoalweight, imperialgoalweight from profile', [], (_, { rows }) => {
          //console.log(rows);
          console.log(rows);

          //console.log(parseFloat(rows._array[0].metricheight));
          profileheight = parseFloat(rows._array[0].metricheight);
          profilestandard = rows._array[0].standard;
          console.log('Profileheight ===>'+profileheight);
          console.log('Profilestandard ===>'+profilestandard);

          // what you resolve here is what will be the result of
          // await getProfileHeightStandardfromDB(); 
          resolve({ profileheight, profilestandard });
      });
    }, null, null);
  });      
}
0
Vivek Doshi On

You need to return data from getProfileHeightStandardfromDB , db.transaction is also async function, so code outside the db.transaction , will execute first before your console logs.

You need to change getProfileHeightStandardfromDB function like this :

export function getProfileHeightStandardfromDB() {
    return db.transaction(
        tx => {

            tx.executeSql('select standard, metricweight, metricheight, imperialheight, imperialweight, bmi, metricgoalweight, imperialgoalweight from profile', [], (_, {
                rows
            }) => {
                //console.log(rows);
                console.log(rows);

                //console.log(parseFloat(rows._array[0].metricheight));
                profileheight = parseFloat(rows._array[0].metricheight);
                profilestandard = rows._array[0].standard;
                console.log('Profileheight ===>' + profileheight);
                console.log('Profilestandard ===>' + profilestandard);
                const profileobject = {
                    profileheight,
                    profilestandard
                };
                console.log(profileobject);
                return profileobject;
            });
        },
        null,
        null
    );
}

Also change the order of last two lines of fetchProfileData :

async fetchProfileData() {
    console.log('Before Profile Fetch');
    const result = await getProfileHeightStandardfromDB();
    console.log('After Profile Fetch');
    console.log('Height : '+result.profileheight);
    console.log('Standard: '+result.profilestandard);
    this.setState({profileobject:result}); //Line Y
    return result; //Line X
}