Я использую React Native, и я только что перенес некоторые функции базы данных в отдельный файл, вместо того, чтобы просто иметь их в файлах, где они мне нужны (мне нужно было использовать одни и те же функции в нескольких файлах, и я предпочел бы все в одном месте). Проблема в том, что функция, которая должна сравнивать одноразовый ключ с ключом в базе данных, всегда возвращает неопределенный.
Я пробовал возвращать функции вместо логических значений и пытался использовать ключевые слова "async/await" (о которых я очень мало знаю).
Вот мой код...
/проект/источник/компоненты/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.info(text, code_snapshot.val().value, text == code_snapshot.val().value);
if (text == code_snapshot.val().value) {
codeIsFound = true;
identifier = code_snapshot.key;
}
});
//console.info(codeIsFound); // this is correct
return codeIsFound; // this always returns undefined
});
};
}
module.exports = Database;
/проект/источник/компоненты/формы/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.info(db.validCode(text.nativeEvent.text))}} // "undefined"
autoCapitalize = "none"
autoCorrect = {false}
/>
</View>
);
}
}
const styles = StyleSheet.create({\
// yay styles :)
});
export default withNavigation(LoginForm);
Всякий раз, когда я помещаю оператор возврата после в функцию firebase "once", она возвращает логическое значение, но по какой-то причине оно всегда ложно. Любая помощь приветствуется!
Обращаясь к этому: Всякий раз, когда я помещаю оператор return после функции firebase «once», он возвращает логическое значение, но по какой-то причине оно всегда ложно.
Удалив код метода .once()
, вы сможете ясно понять, почему это так. Код выполняется точно так же, как если бы он был написан, как показано ниже. Из-за асинхронного характера метода .once()
оператор return
выполняется до разрешения (завершения) .once()
.
isValidCode(text) {
let codeIsFound = false;
let identifier = "";
// .once() goes here
return codeIsFound;
};
Ваше чутье было хорошим насчет async/await. Чтобы устранить проблему, сделайте следующее:
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;
};
Затем функция вернет обещание, которое будет разрешено (или отклонено). Итак, чтобы использовать этот код, выполните следующие действия:
isValidCode('something').then(result => {
/* use result here */
};
Ну конечно; естественно. Вот как работает асинхронно/ожидание. Чтобы использовать значение, сделайте следующее: isValidCode('stuff').then(result=>{ /* use result here */}
Это точно ближе, но возвращает Object { "-LemIGLQEdkCniOFoi8d": Object { "value": "broIMI", }, "-LemIbAmrtC9ABe9EXM2": Object { "value": "7xMbif", }, }
. Я определенно мог бы использовать этот массив/объект с ключами для сравнения внутри KeyForm.js, но я действительно хотел, чтобы об этом позаботились внутри Database.js и чтобы возвращалось логическое значение. Любой способ добиться этого?
ARg - конечно - я вернул обещание от .once()
. В DS Passionate есть исправление — я добавлю сюда для полноты картины.
once()
возвращает Promise<DataSnapshot>
, что означает, что он асинхронный, и вы не можете вернуть значение из асинхронного метода.
Чтобы решить вашу проблему, вы можете сделать следующее:
isValidCode(text) {
let codeIsFound = false;
let identifier = "";
this.codesRef.once('value', (db_snapshot) => {
db_snapshot.forEach((code_snapshot) => {
//console.info(text, code_snapshot.val().value, text == code_snapshot.val().value);
if (text == code_snapshot.val().value) {
codeIsFound = true;
identifier = code_snapshot.key;
takeValue(codeIsFound);
}
});
});
};
takeValue(value){
console.info(value) //true
}
Здесь вы создаете новый метод внутри once()
, а затем добавляете значение в качестве аргумента.
К сожалению, с этой модификацией код по-прежнему возвращает значение undefined. Он успешно записывает значение в консоль, но я до сих пор не знаю, как его вернуть.
куда ты его возвращаешь?
Я попытался вернуться в то же место, что и в вопросе, и внутри условия if (text==code_snapshot.val().value) {}.
как я уже сказал, вы не можете этого сделать, так как это асинхронно, если вы хотите использовать значение codeisfound
где-то еще, добавьте его в качестве аргумента к методу и используйте его в этом методе, как в моем ответе
Хорошо, но как мне получить доступ к этому значению из KeyForm.js? Должен ли я изменить значение onSubmitEditing?
так как вы экспортируете Database
, то в KeyForm.js
используйте метод takeValue
Согласно @randy casburn, проблема такая же. Просто изменение решения, данного @randy.
async isValidCode(text) { let codeIsFound = false; let identifier = ""; if (await this.codesRef.once function call ) {
Return true;
} else {return false;} };
Я думаю, что это близко, но это заставляет функцию возвращать объект «Promise» вместо логического значения.