Ad

Why Does My React Native Function Always Return Undefined?

I am using react native and I have just migrated some database functions to a individual file, instead of just having them in the files where I need them (I have started needing to use the same functions in multiple files, and I'd rather have them all in one place). The problem is, the function that is supposed to compare a one time key with one in the database, always returns undefined.

I have tried returning functions instead of booleans, and have attempted to use "async/await" keywords (which I know very little about).

Here is my code...

/project/src/components/Database.js

var firebase = require('firebase');

if (!firebase.apps.length) {
    firebase.initializeApp({
        apiKey: "key",
        authDomain: "domain",
        databaseURL: "url",
        storageBucket: "bucket",
    });
}

class Database {
    constructor() {
      this.codesRef = firebase.database().ref('codes');
    }
    isValidCode(text) {
        let codeIsFound = false;
        let identifier = "";
        this.codesRef.once('value', (db_snapshot) => {
          db_snapshot.forEach((code_snapshot) => {
            //console.log(text, code_snapshot.val().value, text == code_snapshot.val().value);
            if (text == code_snapshot.val().value) {
              codeIsFound = true;
              identifier = code_snapshot.key;
            }
          });
          //console.log(codeIsFound); // this is correct
          return codeIsFound; // this always returns undefined
        });
    };
}

module.exports = Database;

/project/src/components/forms/KeyForm.js

import React from 'react';
import {
  StyleSheet,
  View,
  TextInput,
} from 'react-native';

import { withNavigation } from 'react-navigation';

import database from '../Database.js';

const db = new database();


class LoginForm extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <View style={styles.container}>
        <TextInput
          style={styles.input}
          placeholder="Access Code"
          returnKeyType="go"
          onSubmitEditing={text => {console.log(db.validCode(text.nativeEvent.text))}} // "undefined"
          autoCapitalize="none"
          autoCorrect={false}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({\
  // yay styles :)
});

export default withNavigation(LoginForm);

Whenever I put a return statement after the firebase "once" function, it does return a boolean, but for some reason it is always false. Any help is greatly appreciated!

Ad

Answer

Addressing this: Whenever I put a return statement after the firebase "once" function, it does return a boolean, but for some reason it is always false.

By removing the .once() method code, you can clearly see why this is the case. The code executes exactly as if it were written like below. Due to the async nature of the .once() method, the return statement executes prior to the .once() resolving (completing).

isValidCode(text) {
  let codeIsFound = false;
  let identifier = "";
  // .once() goes here
  return codeIsFound;
};

Your instinct was a good one about async/await. To fix your issue, do this:

async isValidCode(text) {
  let codeIsFound = false;
  let identifier = "";
  let db_snapshot = await this.codesRef.once('value');
   db_snapshot.forEach(code_snapshot => {
       if (text == code_snapshot.val().value) {
          codeIsFound = true;
          identifier = code_snapshot.key;
        }
   });
   return codeIsFound; 
};

Then, the function will return a promise that will be resolved (or rejected). So to use this code do:

isValidCode('something').then(result => {
   /* use result here */
};
Ad
source: stackoverflow.com
Ad