React: How to save value from async function and use later - javascript

I have an async function that calls an api getting me the current role of a user. Later on I want to attach that role to a variable. Here's my code
const getRole = async () => {
const response = await roleService.getRole();
const roles = await response.role
return roles
}
...........
const currentRole = getRole() //I want this to be the value from return roles
I'm new to react and having trouble with this. How can I set currentRole to the value in return roles?

I would opt to save the information that you got from the API on a state
const [roles, setRoles] = useState();
const getRole = async () => {
const response = await roleService.getRole();
const roles = await response.role
setRoles(roles);
}
you can call the gerRole function on a useEffect like this
useEffect(() => {
getRole();
}, []);
or you can call the getRole function on a button click
<button onClick={getRole}>Click me to get roles</button>

Related

How to get phone number from User Account in Moralis using React Hooks?

I have two functions. One that is used to to insert a phone number (TEL) into Moralis _User collection on the Moralis Database and another function which is used to query data from it.
This is the one I use to insert data. It works perfectly.
const updateTEL = async() => {
const User = Moralis.Object.extend('_User');
const query = new Moralis.Query(User);
query.equalTo("ethAddress", account);
query.exists("TEL");
const object = await query.first();
object.set("TEL", phoneNumber.phone);
object.save();
console.log("phone number updated successfully" , object);
return monster;
}
Now I am having a problem with this function below.
const queryTEL = async() => {
if(isInitialized) {
const User = Moralis.Object.extend('_User');
const query = new Moralis.Query(User);
query.equalTo("ethAddress", account);
const object = await query.first();
if (object) { setExistingTEL(object.TEL);}
return object;
}
}
const basicQuery = async () => {
const results = await queryTEL();
console.log (" results ", results);
};
I don't know why but it returns the result of 'results' as 'undefined'.
Here is how my useEffect looks like.
useEffect(() => {
setVerificationCode(Math.floor(Math.random()*10000));
basicQuery();
}, []);
Am I doing something wrong?

Passing external data into components

In my react app, I am currently passing a list of stores by calling the API directly from the URL.
const getStore = async () => {
try {
const response = axios.get(
'http://localhost:3001/appointment-setup/storeList'
);
return response;
} catch (err) {
console.error(err);
return false;
}
};
I pass this function into my useEffect hook where I would set my get a list of stores using resp.data.stores:
const [storeLocations, setStoreLocations] = useState([]);
useEffect(() => {
async function getData(data) {
await service.stepLocation.init();
const resp = await getStore();
setStoreLocations(resp.data.stores);
}
setFlagRender(true);
return getData();
}, []);
This works, however, I noted in useEffect there is a call await service.stepLocation.init(). There is a file that already takes care of all the backend/data for the component.
const stepLocation = {
// removed code
// method to retrieve store list
retrieveStoreList: async function ()
let response = await axios.get(
constants.baseUrl + '/appointment-setup/storeList'
);
return response.data.stores;
,
// removed code
Since this data is available, I don't need the getStore function. However when I try to replace response.data.stores in useEffect with service.stepLocation.retrieveStoreList no data is returned. How do I correctly pass the data from this file in my useEffect hook?
I think your useEffect should be like follows as you want to save the stores in your state.
useEffect(() => {
const updateStoreLocations = async () => {
const storeLocations = await service.stepLocation.retrieveStoreList();
setStoreLocations(storeLocations);
}
updateStoreLocations();
}, [])

How to declare a variable from a firestore query?

this piece of code works when I press save in visual studio code. But If I refresh the preview page in the browser it shows me this error: Unhandled Rejection (FirebaseError): Function Query.where() called with invalid data. Unsupported field value: undefined
let { id } = useParams();
const [video, setVideo] = React.useState([]);
const [show, setShow] = React.useState([]);
const classes = useStyles();
React.useEffect(() => {
const fetchData = async () => {
const db = firebase.firestore();
const data = await db
.collection("videos")
.where('path', '==', id)
.get()
setVideo(data.docs.map(doc => doc.data()));
}
fetchData()
}, [])
let showUrl = video.map(video =>(video.uploadBy));
console.log(showUrl[0]);
let videoDate = video.map(video =>(video.date.toDate()));
console.log(videoDate[0]);
React.useEffect(() => {
const fetchData = async () => {
const db = firebase.firestore();
const data = await db
.collection("shows")
.where('urlPath', '==', showUrl[0])
.get()
setShow(data.docs.map(doc => doc.data()));
}
fetchData()
}, [])
I think that the problem is that I'm trying to declare the variable "showUrl" in the wrong way. The console.log(showUrl[0]) works perfectly. It prints exactly the value that I need.
Both these useEffect calls fire as soon as the component mounts. If you are getting the id for your first useEffect from url parameters or such, it's probably there immediately and the call Firestore query should work.
However, when your second useEffect fires, the state 'video' is still set to an empty array. Therefore the showUrl variable is also an empty array, and showUrl[0] is undefined.
What you could do for your second useEffect is this:
React.useEffect(() => {
const fetchData = async () => {
const db = firebase.firestore();
const data = await db
.collection("shows")
.where('urlPath', '==', showUrl[0])
.get()
setShow(data.docs.map(doc => doc.data()));
}
video.length && fetchData()
}, [video])
So you are only calling the fetchData() function if the array in 'video' state has more than 0 items, and you add it to the useEffect dependency array, so the useEffect gets ran every time 'video' changes.

How can I call async function inside a loop?

I have below code in node. In getPosts, it reads 10 posts from database which is an async function call. And for each post, it needs to read user info. from database which is another async function call. How can I make it work in node js?
const getUser = async (userId) => {
// read user from database
}
const getPosts =async () => {
const posts = await getPostsFromDB(10); // get 10 posts from database
for(let i=0; i<posts.length; i++){
posts[i].user = await getUser(posts[i].userId) // ERROR: I can't call await inside a loop
}
}
I am thinking about using Promise.all() like below:
const getPosts =async () => {
const posts = await getPostsFromDB(10); // get 10 posts from database
const allProms = posts.map(post => getUser(post.userId));
Promise.all(allProms); // how can I assign each user to each post?
}
but I don't know how I can assign each user to each post after calling Promise.all().
Consider approaching the problem slightly differently. If you wait for responses in an iterative loop, it'll produce poor performance. Instead, you could push them all into an array and wait for them — so they're all fetching at the same time.
const getUser = async (userId) => {
try {
// read
} catch (e) {
// catch errors
}
// return data
}
const getPosts = async () => {
const posts = await getPostsFromDB(10); // get 10 posts from database
const userRequests = posts.map((post, index) => getUser(post.userId))
const users = await Promise.all(userRequests)
return posts.map((post, index) => {
post.user = users[index]
})
}
If you think you may have duplicate userIds, consider forming a list of users you can reference before calling getUser.

use date from fetch object to create link for fetch another object in react

I write some code and works but i think maybe can be done on some better way. What i want from code? I create link and fetch object from that object i want use some value and pass that value in another link after that fetch new object. My code working but i want see if is possible new solution.
const [key, setKey] = useState("");
const [data, setData] = useState([]);
useEffect(() => {
getKey();
getWeather();
},[key]);
//this function get key from object and that key i will use in another link
const getKey = () => {
navigator.geolocation.getCurrentPosition(
(position) => {
const long = JSON.stringify(position.coords.longitude);
const lat = JSON.stringify(position.coords.latitude);
const proxy = `https://cors-anywhere.herokuapp.com/`;
const link = `${proxy}http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=rhlYEhvAu0nhFNMFybOIhffbmjFX0AZN&q=${lat}%2C${long}&details=true`;
(async function fetchData(){
const getValue = await fetch (link);
const key = await getValue.json();
setKey(key.Key);
})();
}
);
};
const getWeather = async () => {
const proxy = `https://cors-anywhere.herokuapp.com/`;
const link = `${proxy}http://dataservice.accuweather.com/forecasts/v1/daily/5day/${key}?apikey=rhlYEhvAu0nhFNMFybOIhffbmjFX0AZN&details=true&metric=true`;
const data = await fetch (link);
const getData = await data.json();
setData(getData);
};
You can make this work by just making a few slight changes to your code. Make the useEffect and async function, return the key from getKey to a variable and await the variable assignment and pass to getWeather. Something like this:
const [key, setKey] = useState("");
const [data, setData] = useState([]);
useEffect(async() => { // <---- Converted to async
const apiKey = getKey(); // <---- Assigned to variable
getWeather(await apiKey); // <--- Using apiKey in function rather than just state
},[key]);
const getKey = () => {
navigator.geolocation.getCurrentPosition(
(position) => {
const long = JSON.stringify(position.coords.longitude);
const lat = JSON.stringify(position.coords.latitude);
const proxy = `https://cors-anywhere.herokuapp.com/`;
const link = `${proxy}http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=rhlYEhvAu0nhFNMFybOIhffbmjFX0AZN&q=${lat}%2C${long}&details=true`;
(async function fetchData(){
const getValue = await fetch (link);
const key = await getValue.json();
setKey(key.Key);
return key.Key //<------ returned key for useEffect
})();
}
);
};
const getWeather = async (apiKey = key) => { // <----If no value passed to function, will use state value
const proxy = `https://cors-anywhere.herokuapp.com/`;
const link = `${proxy}http://dataservice.accuweather.com/forecasts/v1/daily/5day/${apiKey}?apikey=rhlYEhvAu0nhFNMFybOIhffbmjFX0AZN&details=true&metric=true`;
const data = await fetch (link);
const getData = await data.json();
setData(getData);
};
The reason I returned the value rather than using state is because setting state is asynchronous and there is currently no callback function for the useState setting function like there was for setState.

Categories