I am new to ES6 and react-native, trying to get multiple values from the SecureStore.
I think I am misunderstanding promises here ... global.userData is empty in the Promise.all(promises).then function. The relevant values do exist in the secure store
My code is:-
getUserData(fields) {
var promises = [];
var that = this;
global.userData = {};
function getField(field) {
return SecureStore.getItemAsync(field)
.then(res => {
console.log(field+"="+res); // this appears after the log below
global.userData[field] = res;
})
.catch(error => {
global.userData[field] = null;
});
}
fields.map(field => {
promises.push[getField(field)];
});
Promise.all(promises).then(function(v) {
console.log(global.userData); // this is empty
that.setState({ isReady: true }); // allow page to render
});
}
getUserData(["userId", "userName","etc"]);
My bad ... inadvertantly used
promises.push[getField(field)];
should have been:
promises.push(getField(field));
Suprised it wasn't detected as a syntax error ...
Related
I was trying to make an app which lists a user's repositories from github using github API, however I'm having a big problem with fetching data from all pages (so far I can only get repos from one page). I tried to fix it by using an async/await function (instead of Promise), but it's also my first time using vue3 and I have no idea how to have a function inside of the setup() method.
The current code is here:
https://github.com/agzpie/user_repos
My try at using async/await, which didn't work:
import ListElement from "./components/ListElement";
import { ref, reactive, toRefs, watchEffect, computed } from "vue";
export default {
name: "App",
components: {
ListElement,
},
setup() {
const name = ref(null);
const userName = ref(null);
const state = reactive({ data: [] });
let success = ref(null);
const userNameValidator = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i;
const split1 = reactive({ spl1: [] });
const split2 = reactive({ spl2: [] });
async function myFetch() {};
/*
* Check for input in the form and then fetch data
*/
watchEffect(() => {
if (!userName.value) return;
if (!userNameValidator.test(userName.value)) {
console.log("Username has invalid characters");
return;
}
let hasNext = false;
state.data = [];
do {
async function myFetch() {
let url = `https://api.github.com/users/${userName.value}/repos?per_page=5`;
let response = await fetch(url);
if (!response.ok) {
success.value = false;
throw new Error(`HTTP error! status: ${response.status}`);
}
success.value = true;
// check response.headers for Link to get next page url
split1.spl1 = response.headers.get("Link").split(",");
let j = 0;
while (j < split1.spl1.length) {
split2.spl2[j] = split1.spl1[j].split(";");
console.log(split2.spl2[j][0]);
console.log(split2.spl2[j][1]);
if (split2.spl2[j][1].includes("next")) {
let urlNext = split2.spl2[j][0].replace(/[<>(\s)*]/g, "");
console.log(urlNext);
url = urlNext;
hasNext = true;
break;
} else {
hasNext = false;
}
j++;
}
// second .then
let myData = await response.json();
state.data.push(...myData);
console.log("data", myData);
name.value = "";
}
myFetch().catch((err) => {
if (err.status == 404) {
console.log("User not found");
} else {
console.log(err.message);
console.log("oh no (internet probably)!");
}
});
} while (hasNext);
});
// Sort list by star count
const orderedList = computed(() => {
if (state.data == 0) {
return [];
}
return [...state.data].sort((a, b) => {
return a.stargazers_count < b.stargazers_count ? 1 : -1;
});
});
return {
myFetch,
success,
isActive: true,
name,
userName,
ListElement,
...toRefs(state),
orderedList,
};
},
};
Any help would be highly appreciated
The call to myFetch() near the end is a call to an async function without an await, so it is effectively going to loop (if hasNext was initialized to true, but it isn't) without waiting for it to complete.
You should probably change that line to await myFetch() and wrap it all with a try/catch block.
I also don't really care for the way you're directly updating state inside the async myFetch call (it could also be doing several of those if it looped) and perhaps it should be returning the data from myFetch instead, and then you can use let result = await myFetch() and then make use of that when it returns.
Also, instead of awaiting myFetch() result, you could not await it but push it onto a requests array and then use await Promise.all(requests) outside the loop and it is one operation to await, all requests running in parallel. In fact, it should probably be await Promise.allSettled(requests) in case one of them fails. See allSettled for more.
But also I wonder why you're reading it paged if the goal is to fetch them all anyway? To reduce load on the server? If that is true, issuing them paged but in parallel would probably increase the load since it will still read and return all the data but require multiple calls.
What I am trying to do is sync a list of attendees from an online database, and if the current user is in the list, then disable a button, else enable the button.
I am using react native hook (I am not sure if I am using the term correctly as I am fairly new to react), in order to set the value of disabling the button.
The issue that I am facing is that the value is getting initialized to false, even tho it should clearly get initialized to true.
After adding some logging I made sure that the function is executing correctly and reaching the code where it sets the value to true.
const [buttonDisabled, changeButtonState] = useState( () => {
var database = firebase.database();
var userId = firebase.auth().currentUser.uid;
const dbRef = firebase.database().ref();
var Attendees = [];
var disable = false;
dbRef.child("gameAttendees").child(gameinfo.gameID).get().then((snapshot) => {
if (snapshot.exists()) {
Attendees = snapshot.val().Attendees;
for(var i=0;i<Attendees.length;i++){
if(Attendees[i]==userId){
return true;
}
}
} else {
console.log("no value");
return false;
}
}).catch((error) => {
console.error(error);
});
});
Adding an example of an async mount effect:
const Comp = () => {
const [s, setS] = useState(); // State will be undefined for first n renders
useEffect(() => {
// Call the async function and set the component state some time in the future
someAsyncFunction().then(result => setS(result));
}, []); // An effect with no dependencies will run only once on mount
return </>;
};
I want to write a function that will get the value for the collection, as shown in the picture:
And here is my code, I really don't know what to do after the "then()":
const getLocation = () => {
firebase
.firestore()
.collection("users")
.doc(currentUser.uid)
.get()
.then((querySnapshot) => {});
};
Note that currentUser is redux, meaning that the query will execute only for the current user that is logged in
If you want to return the value of businessLocation only you can do this:
const getLocation = () => {
return firebase.firestore()
.collection("users")
.doc(currentUser.uid)
.get()
.then(function(doc) {
if (doc.exists) {
data = doc.data();
return data.businessDetails.businessLocation;
} else {
return "";
}
});
};
You can get more information on how to get data in firestore at the Official Documentation.
Note: This makes your function become an asynchronous function. Therefore you should call it as follows:
getLocation().then(result => {
//Do whatever you want with the result value
console.log(result);
})
Curious issue I'm having dealing with some callback functions. I need to make a series of API calls that all return promises then I'm trying to take that data and map it to an array that exists on the global scope followed by a function to export the new data as a pdf - my issue is that the then() block is firing before the other function finishes and far before the first API call finshes. `
let fireWatson = async () => {
let watsonClassifed = []
let watsonCallIndex = 0;
let returnedArr = []
for (let i = 0; i < watsonData.length; i++) {
let params = {
classifierId: '***********',
collection: watsonData[i]
}
naturalLanguageClassifier.classifyCollection(params,
function (err, response) {
if (err)
console.log('error:', err);
else
console.log("data returned")
console.log(response.result.collection)
watsonClassifed.push(response.result.collection);
console.log(watsonClassifed)
})
}
}
fireWatson(watsonData).then(res =>
console.log("firing stupid callbback after data")
)
I realize this function isnt actually returning anything but is it possible to still make use of a promise without a return value or is this the main issue im hitting? Ideally - i want the then function to wait until the data is back - mapped to the global array and then outputted but this of course depends on proper synchronicity.
output:
[Done] exited with code=0 in 1.526 seconds
[Running] node "index.js"
firing stupid callbback
data returned
all my sweet sweet data
All functions in JavaScript have returns, it's just that they are implicit if you don't say return explicitly
It's always a bit tricky to mix promises with callbacks. Here is a way you can fireWatson without using any utilities.
let fireWatson = async watsonData => Promise.all(watsonData.map(collection => new Promise((resolve, reject) => {
let params = {
classifierId: '***********',
collection: collection,
}
return naturalLanguageClassifier.classifyCollection(params, function(err, response) => {
if (err) {
reject(err)
} else {
resolve(response)
}
})
})))
Of course, you can simplify this tremendously using a utility I created
const { map } = require('rubico')
let fireWatson = map(collection => new Promise((resolve, reject) => {
let params = {
classifierId: '***********',
collection: watsonData[i]
}
return naturalLanguageClassifier.classifyCollection(params, function(err, response) => {
if (err) {
reject(err)
} else {
resolve(response)
}
})
}))
turns out console.log was firing because every .then() block expects a function.
wrong:
fireWatson(watsonData).then(res =>
console.log("firing stupid callbback after data")
)
right:
fireWatson(watsonData).then(()res =>
console.log("firing stupid callbback after data")
)
How to remove an item from AsyncStorage? right now I am trying this code:
AsyncStorage.removeItem('userId');
but this is not working for me.
Try this:
async removeItemValue(key) {
try {
await AsyncStorage.removeItem(key);
return true;
}
catch(exception) {
return false;
}
}
This is what I did, had a similar issue.It works well when you want to remove an item based on its id. make sure each item has a unique id.
remove_user = async(userid) => {
try{
let usersJSON= await AsyncStorage.getItem('users');
let usersArray = JSON.parse(usersJSON);
alteredUsers = usersArray.filter(function(e){
return e.id !== userid.id
})
AsyncStorage.setItem('users', JSON.stringify(alteredUsers));
this.setState({
users:alteredUsers
})
}
catch(error){
console.log(error)
}
};
This looks correct, but maybe you are trying to read back from AsyncStorage too soon? It's asynchronous, so the change isn't applied right away and you might still see the key if you try to get it on the following line. Try to call AsyncStorage.removeItem with await or do what you want to do in the callback.
this delete method which removes object from array by passing index (here i called id)
async deleteData(id) {
try {
this.state.item.splice(id, 1);
await AsyncStorage.setItem("mylist",JSON.stringify(this.state.item))
this.setState({ item: JSON.parse(await AsyncStorage.getItem("mylist")) })
} catch (error) {
console.log(error);
}
};
and call this by using onPress method, here i am using button and pass index
<Button onPress={this.deleteData.bind(this,index)}>delete</Button>
This is the framework code for AsyncStorage.removeItem:
removeItem: function(
key: string,
callback?: ?(error: ?Error) => void
): Promise {
return new Promise((resolve, reject) => {
RCTAsyncStorage.multiRemove([key], function(errors) {
var errs = convertErrors(errors);
callback && callback(errs && errs[0]);
if (errs) {
reject(errs[0]);
} else {
resolve(null);
}
});
});
}
As you can see above it requires the key(Which is name of the item you set in asyncstorage that you want to delete) and a callback function. Make sure you have the correct key and the correct params and it should work fine.
Use removeItem() method to remove values from AsyncStorage in react.
try {
await AsyncStorage.removeItem(key);
console.log('Data removed')
}
catch(exception) {
console.log(exception)
}
try this for react-native
const deletCar = async () => {
try {
await AsyncStorage.removeItem('#storage_Key').then(() => {
// props.navigation.navigate('same page name refresh ');
/* setprevCar({ carNumner: '', carModel: '' }) return empty obj if deleted. */
})
}
catch (exception) {
return false;
}
}
if you want to remove the selected list :-
let key =[
'visitorId',
'visitorMobile',
'visitorData',
]
await AsyncStorage.multiRemove(key)