Je suis nouveau dans React-Native et je ne savais pas trop comment avoir une variable accessible par toutes les fonctions d'un fichier sans être dans une classe.
Mon problème est que j'ai attribué du stockage dans taskFour () et je veux que cette valeur soit renvoyée dans runDemo () mais pour une raison quelconque, lorsque je console.log (stockage) dans runDemo (), elle renvoie undefined!
J'ai défini un fichier d'aide avec un tas de fonctions qui font appel les unes aux autres.
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,
}
J'ai pensé en attribuant un "stockage" en dehors du fonctions en feraient une variable accessible à toutes les fonctions de ce fichier sans en faire une variable globale. De plus, une restriction que j'ai est que je ne peux pas retourner le stockage de queryPeopleSuccess jusqu'à runDemo en raison de fonctions dans ces fonctions qui ne sont pas supposées avoir une valeur de retour!
Quelqu'un pourrait-il indiquer s'il vous plaît comment puis-je avoir une variable dans un fichier qui n'a pas besoin d'être dans une classe accessible et éditée par les fonctions de ce fichier?
EDITED: édité pour plus de clarté et de fautes de frappe. Il s'avère que le problème avec mon code est dû à une asynchrone!
3 Réponses :
taskFour n'est jamais appelé? Vous appelez taskThree depuis taskTwo .
Mes excuses, je résume mon code rn. J'ai modifié le code ci-dessus pour le refléter avec précision
Cela ne suffit pas car sans modification, taskOne , etc.
Bien sûr, je n'ai pas dit qu'il avait changé son code et je lui ai laissé comprendre le problème.
Votre problème est que runDemo est retourné depuis longtemps avant que queryPeopleSuccess n'écrive même dans le stockage . Donc, vous le lisez avant qu'il ne soit écrit, et comme les informations ne peuvent pas voyager dans le temps, vous obtenez indéfini . En gros, vous avez ce problème.
Vous pourriez grandement simplifier votre code en utilisant une fonction asynchrone à la place:
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
}
}
Ensuite, vous appelleriez runDemo comme console.log (attendez runDemo ()) dans une autre fonction asynchrone, ou runDemo (). then (results => console.log (results), err => console.error (err)) sinon.
Je vois. Merci beaucoup! J'importe helper.js dans mon App.js et je me demandais si je pourrais simplement l'appeler avec const data = Helper.runDemo (); ou il semble que j'ai besoin de quelque chose lié aux promesses ou à l'asynchrone!
Oui, vous aurez à nouveau le même problème - une fois qu'une chose est asynchrone, tout qui dépend du résultat de cette chose (directement ou indirectement) doit également devenir asynchrone.
Ahhhh ok. Je vous remercie beaucoup pour votre aide! Je vais certainement lire sur ceux-ci
Votre hypothèse est correcte, quel est exactement le problème auquel vous êtes confronté? Vous avez seulement décrit ce qui devrait arriver, mais pas ce qui se passe réellement à la place.
Excuses! Ce qui se passe réellement, c'est que lorsque je console.log (stockage) dans la fonction runDemo (), il renvoie undefined alors qu'il est supposé renvoyer la valeur à laquelle je lui ai assigné dans taskFour ()
Après avoir réparé les pièces manquantes (
taskThree,localArray) cela fonctionne pour moi comme prévu: jsfiddle.net/c59fLujr - Veuillez créer un exemple minimal et reproductible qui démontre le problème .Peut-être avez-vous un
let storage/var storageou un argument de fonctionstorageà l'intérieur de votre véritabletaskFour, donc vous êtes attribuer à cette variable au lieu de la variable globale? - Ou: Peut-être qu'une partie de votre flux de travail est asynchrone et que vous écrivez dans lestockageaprès que votrerunDemoest revenu depuis longtemps ...Malheureusement, je ne
Alors essayez de supprimer des parties de votre code jusqu'à ce que vous arriviez à un exemple minimal et reproductible qui fonctionne dans un JSFiddle comme mon test ci-dessus. Mon test fonctionne, donc la seule façon de comprendre pourquoi votre code ne fonctionne pas est de le voir exécutable dans JSFiddle de manière non fonctionnelle et de l'analyser là-bas.
Mon code utilise une bibliothèque de stockage react-native-sqlite qui, je pense, ne peut pas être reproduite dans JSFiddle, mais je peux modifier mon code ci-dessus pour en afficher plus
Vous pourriez vous en moquer, l'idée est de créer un exemple minimal, la façon dont cette bibliothèque fonctionne en interne n'est probablement pas pertinente. Et si en minimisant votre exemple votre bogue disparaît, alors vous avez trouvé le bogue! Mais votre mention de cette bibliothèque et du fait que c'est apparemment une partie importante de ce flux de tâches donne l'impression qu'il y a une asynchronicité impliquée. Si vous avez un code comme
function taskOne () {tx.executeSql ('SELECT 1', [], function (tx, results) {taskTwo (results)})}alors c'est le problème: < code> taskOne retourne avant même quetaskTwone soit appelé.Je n'essaye pas de me moquer de quoi que ce soit, je pensais simplement que mon exemple était déjà au minimum sans compliquer les choses avec la bibliothèque. Je n'ai jamais traité d'asynchronicité et je ne sais vraiment pas comment procéder
En plus d'utiliser le mauvais nom de variable (
database?), Le code est asynchrone (c'est pourquoi vous devez passer un rappel). Le retour synchrone du résultat d'une fonction asynchrone n'est pas possible. Renseignez-vous sur les promesses etasynchroniser / attendreMa faute. J'ai changé certains noms de variables et j'ai oublié de changer celui-ci en stockage. Cependant, je ne pense pas que ce soit le problème ... Mais merci, je vais lire sur Promises et asynchroniser / attendre en attendant