1

I'm new to React-Native and I was confused on how to have a variable that can be accessed by all the functions within a file without being in a class.

My issues is that I assigned storage in taskFour() and I want that value to be returned in runDemo() but for some reason when I console.log(storage) in runDemo() it returns undefined!

I have defined a helper file with a bunch of functions that call upon each other.

Helper.js

import React from 'react';
import SQLite from 'react-native-sqlite-storage';

let db;
let storage;

function runDemo() {
  loadAndQueryDB();
 //Suppose to return value assigned in queryPeopleSuccess but console logs 'undefined'
  console.log(storage);
  return storage;
}

//    Sends an update saying that Database was successfully opened
function openCB() {
  console.log("Success Opening DB");
}

//      Sends an update with error message and returns FALSE
function errorCB(err) {
  console.log("SQL Error: ", err);
  return false;
}

/** 2. Called when runDemo is called **/
/*   assigns variable 'db' to opened Database */
/*   Calls queryPeople(db) */
function loadAndQueryDB() {
  console.log("Opening Database...: ");
  
  db = SQLite.openDatabase({ name: "users.db", createFromLocation: 1}, openCB, errorCB);
  queryPeople(db);
}

/** 3. Called when loadAndQueryDB is called **/
/*    Get the DB and applies a SQL call that if successful will call queryPeopleSuccess*/
function queryPeople(db) {
  console.log("Executing employee query...");
  //Execute a database transaction.
  db.transaction((tx) => {
    tx.executeSql('SELECT * FROM users', [], queryPeopleSuccess, errorCB);
  });

}

function queryPeopleSuccess(tx, results) {
  var len = results.rows.length;
  let localArray = [];
  //Go through each item in dataset
  for (let i = 0; i < len; i++) {
    let row = results.rows.item(i);
    localArray.push(row);
  }

  storage = localArray;
}

export {
  runDemo,
}

I thought by assigning "storage" outside of the functions would make it a variable accessible to all the functions in this file without making it a global variable. In addition, one restriction I have is that I can't return storage from queryPeopleSuccess all the way back to runDemo due to functions within these functions that are not suppose to have a return value!

Could someone please point out how I can have a variable within a file that does not need to be in a class that can be accessed and edited by the functions within that file?

EDITED: Edited for clarity and typos. Turns out the issue with my code is due to async!

11
  • Your assumption is correct, what exactly is the problem you are facing? You only described what should happen but not what actually happens instead. Commented Jun 29, 2020 at 22:21
  • Apologies! What actually happens is that when I console.log(storage) in the runDemo() function it returns undefined when it is suppose to return the value i assigned it to in taskFour() Commented Jun 29, 2020 at 22:22
  • After fixing the missing parts (taskThree, localArray) it works for me as expected: jsfiddle.net/c59fLujr - Please create a minimal, reproducible example that demonstrates problem. Commented Jun 29, 2020 at 22:25
  • Maybe you have a let storage/var storage or a function argument storage inside your real taskFour, so you are assigning to that variable instead of the global one? - Or: Maybe part of your workflow is asynchronous, and you are writing to storage after your runDemo has long returned... Commented Jun 29, 2020 at 22:26
  • Unfortunately, I don't Commented Jun 29, 2020 at 22:27

3 Answers 3

1

Your problem is that runDemo has long returned before queryPeopleSuccess is even writing to storage. So, you are reading it before it gets written, and since information can't travel back in time, you get undefined. Basically you have this problem.

You could greatly simplify your code by using an asynchronous function instead:

import SQLite from 'react-native-sqlite-storage'

export async function runDemo () {
  console.log('Opening Database...: ')

  try {
    // This one is tricky, because it seems the library synchronously
    // returns the db instance, but before that it calls the success or
    // error callbacks (without passing the instance).
    const db = await new Promise((resolve, reject) => {
      const db = SQLite.openDatabase(
        { name: 'users.db', createFromLocation: 1 },
        // The trick here is that in the success case we wait for openDatabase
        // to return so that db will be assigned and we can resolve the promise
        // with it.
        () => setTimeout(() => resolve(db), 0),
        reject
      )
    })
    console.log('Success Opening DB')

    console.log('Executing employee query...')
    // Execute a database transaction.
    const results = await new Promise((resolve, reject) => {
      db.transaction(tx => {
        tx.executeSql(
          'SELECT * FROM users',
          [],
          (tx, results) => resolve(results),
          reject
        )
      })
    })

    const localArray = []
    // Go through each item in dataset
    for (let i = 0; i < results.rows.length; i++) {
      localArray.push(results.rows.item(i))
    }
    return localArray
  } catch (e) {
    console.log('SQL Error: ', e)
    return false
  }
}

Then you would call runDemo as console.log(await runDemo()) inside another async function, or runDemo().then(results => console.log(results), err => console.error(err)) otherwise.

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

3 Comments

I see. Thank you so much! I am importing helper.js into my App.js and I was wondering if I could just call it with const data = Helper.runDemo(); or it seems like I need something related to promises or async!
Yes you will have the same problem there again - once one thing is async, everything that depends on the result of that one thing (directly or indirectly) has to be become async as well.
Ahhhh ok. Thank you so much for your help! I'll definitely read up on these
1

taskFour is never called ? You are calling taskThree from taskTwo.

1 Comment

My apologies I'm summarizing my code rn. I've edited the code above to accurately reflect it
1

Your issue is related to async in Javascript.

Your current program ( script ) is executed from top to bottom with sync mechanism, and you did not assign any initial value to your variable storage. So the function runDemo with return the default value undefined.

To solve your problem you need to convert your runDemo to async Function.

let storage;

async function runDemo() {
    await taskOne();
    //Suppose to return value assigned in taskFour but console logs 'undefined'
    console.log(storage);
    return storage;
}


function taskOne() {
    taskTwo();
}

function taskTwo() {
    taskFour();
}

let localArray = 20;

function taskFour() {

    storage = localArray;
    //Here storage is assigned properly and outputs the data I want
    console.log(storage);
}
runDemo()

2 Comments

That's not enough though since without modification taskOne, etc. won't return a promise.
Of course, I did not that he changed his code and I let him understand just the issue.

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.