getting a value from a field in firebase - reactjs

I am trying to retrieve a specific value of a field and store it inside a variable named joiningScore. This makes joiningScore a object with a promise that has a value in it. How can I get that value. I tried tucking in a .then method after the .get("currentPos") but it throws an error saying docSnapshot.get().then is not a function.
var joiningScore = positionDoc.get().then((docSnapshot) => { return docSnapshot.get("currentPos"); })
const positionDoc = frebase.firestore().collection('position').doc('kY3k3lmnCIVG3Qi6LxUZ');
here positionDoc is a reference to the document in firestore.

This is because you are assigning to a variable a Promise chain.
You need to wait that the Promise returned by the get() method is fulfilled in order to get the value. See this doc for more details.
So something along these line should work:
const positionDoc = firebase.firestore().collection('position').doc('kY3k3lmnCIVG3Qi6LxUZ');
var joiningScore;
positionDoc.get().then((docSnapshot) => {
joiningScore = docSnapshot.get("currentPos");
})
You could also use an async function as follows:
async function getJoiningScore() {
const positionDoc = firebase.firestore().collection('position').doc('kY3k3lmnCIVG3Qi6LxUZ');
const docSnapshot = await positionDoc.get();
return docSnapshot.get("currentPos");
}
Note that this function is itself asynchronous.

Related

get data from promiseresult object of promise.all and axios call

I am using the following code and my aim is to get the data from the data section of the PromiseResult object of the returned Promise. I am using the following code:
const promiseComment = axios.post(`${BASE_URL}/api/addComment/`, data, getDefaultHeaders());
let allPromises = []
allPromises.push(promiseComment)
Promise.all([allPromises])
.then(function (values) {
console.log(values[0][0]);
});
When I console the values, I get the following response, what I need is the data section from the response which I marked in the following image.
Thanks in advance
you need to resolve the promise inside
const promiseComment = axios.post(`${BASE_URL}/api/addComment/`, data, getDefaultHeaders());
let allPromises = []
allPromises.push(promiseComment)
Promise.all([allPromises])
.then(values=>values).then(obj=>console.log(object.data));

Add query parameter in the middle of the URL using react fetch

I am writing a service for all my RestApis where I store RestApis and then use it when I need by calling methods.
RestApiService.js
let getData = 'https://myURL?id=123456';
export const getIndividualUsers = (resourceId) => {
const queryParams = {
userId: resourceId
};
queryParams.authorization = sessionStorage.getItem("authorization");
}
Object.keys(queryParams).forEach((k) => {
queryParams[k] = (typeof (queryParams[k]) !== 'string') ? JSON.stringify(queryParams[k]) : queryParams[k];
});
return getData.get('', queryParams);
};
I call this method when I need data using the method name and use the response in my code:
getIndividualUsers(123456).then((response));
Now one of my API has variable in the middle of the URL such as
URL: 'https://myURL/${variable}/children/12'
How do I pass queryParams(variable) in the middle of the Url? I will have variable value when I call the method that fetches the URL and not while defining the the URL.
Which library are you using? Anyway you can do like below always.
const getChild = (parentName, id) => {
let url = `https://myURL/${parentName}/children/${id}`;
...
};

React: Method finishing before data loaded

I am trying to retrieve some data from Yahoo Finance using an XHTML Request, which works. However, I am trying to display the data retrieved on my app, but the method to retrieve the data is returning "undefined" before the data has been loaded.
async componentDidMount() {
var tempData = await this.fetchAsync();
console.log(tempData)
this.handleLoad(tempData)
}
handleLoad = (num) => {
this.setState(state => ({
price: num
}));
}
async fetchAsync () {
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
const {params} = this.props.navigation.state;
var ticker = params.ticker;
var result;
var tempArray = [1];
var url = "https://yahoo-finance-low-latency.p.rapidapi.com/v8/finance/spark?symbols=" + ticker + "&range=2y&interval=1d"
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
result = JSON.parse(this.responseText);
tempArray = result[ticker]['close'];
testPrice = tempArray[tempArray.length-1]
console.log(testPrice)
var self = this;
return tempArray[tempArray.length-1]
}
});
xhr.open('get', url, true);
xhr.setRequestHeader("x-rapidapi-key", "my key");
xhr.setRequestHeader("x-rapidapi-host", "yahoo-finance-low-latency.p.rapidapi.com");
xhr.send();
}
I am using the componentDidMount() function to begin calling the methods to load the data, but when the app renders, the values are not displayed.
As you can see inside the fetchAsync() method, I return the value I need, but when I try and console.log the return from this method, I get undefined.
I have also tried moving this return to the end of the method, but when I use console.log here to ensure that tempArray has the data I need, it is empty.
I need to display tempArray[tempArray.length-1] on my screen, but the data is not loaded in time, and does not update even after it has loaded.
Your return tempArray[tempArray.length-1] inside the fetchAsync isn't actually returning from fetchAsync -- it's just returning from the callback function inside addEventListener. In fact, you don't actually have any code that is taking advantage of the async tag you have on that function.
One solution to this would be to call handleLoad directly from inside fetchAsync instead of return tempArray. (Of course, you'll want to make sure that you've bound this correctly to handleLoad).
Another solution would be to pass a callback function into fetchAsync that you could call instead of returning. Then, at your call site, it might look something like this:
this.fetchAsync((tempData) => {
console.log(tempData)
this.handleLoad(tempData)
});
Finally, a third solution would be to switch from XMLHTTPRequest to fetch, and then you could take advantage of async/await and actually make that fetchAsync method async (and be able to return a value from it).

Exporting an array within an ".then" doesnt work

I'm new to NodeJS and are only familiar with Java. I'm trying to create a file that creates objects based on a database and adds them to an array. This array I want to be able to export so that I can use it throughout the whole program, but when I try to export the array it doesn't work. I've tried googling and understanding but haven't come across anything that was helpful unfortunately.
I hope that someone can help me understand
I've tried calling module.exports after the ".then" call, but it just returns an empty array because its async.
I've also tried calling module.exports = teams inside the .then call but it didn't work neither.
var teams = [];
function assignTeamsToClasses() {
return new Promise((resolve, reject) => {
getAllTeamsInDb((teamList) => {
teamList.forEach((aTeam) => {
let newTeam = new Team(aTeam['teamid'], aTeam['teamname'], aTeam['teamrank']);
teams.push(newTeam);
});
resolve();
});
})
}
assignTeamsToClasses().then(() => {
module.exports = teams;
});
main.js
var teams = require('./initialize.js');
console.log(teams);
I expect it to return all teams that are in the database. I know that array is not empty when called within the ".then" call, but the export part does not.
Simple
the sequence require() + console.log() is synchronous
assignTeamsToClasses() is asynchronous, i.e. it updates teams at some unknown later point in time.
You'll have to design your module API to be asynchronous, e.g. by providing event listener interface or Promise interface that clients can subscribe to, to receive the "database update complete" event.
A proposal:
module.exports = {
completed: new Promise(resolve =>
getAllTeamsInDb(teams => {
const result = [];
teams.each(aTeam =>
result.append(new Team(aTeam.teamid,
aTeam.teamname,
aTeam.teamrank)
)
);
resolve(result);
})
),
};
How to use it:
const dbAPI = require('./initialize.js');
dbAPI
.completed
.then(teams => console.log(teams))
.catch(error => /* handle DB error here? */);
Every caller who uses this API will
either be blocked until the database access has been completed, or
receive result from the already resolved promise and proceed with its then() callback.

Caching in React

In my react App I have a input element. The search query should be memoized, which means that if the user has previously searched for 'John' and the API has provided me valid results for that query, then next time when the user types 'Joh', there should be suggestion for the user with the previously memoized values(in this case 'John' would be suggested).
I am new to react and am trying caching for the first time.I read a few articles but couldn't implement the desired functionality.
You don't clarify which API you're using nor which stack; the solution would vary somewhat depending on if you are using XHR requests or something over GraphQL.
For an asynchronous XHR request to some backend API, I would do something like the example below.
Query the API for the search term
_queryUserXHR = (searchTxt) => {
jQuery.ajax({
type: "GET",
url: url,
data: searchTxt,
success: (data) => {
this.setState({previousQueries: this.state.previousQueries.concat([searchTxt])
}
});
}
You would run this function whenever you want to do the check against your API. If the API can find the search string you query, then insert that data into a local state array variable (previousQueries in my example).
You can either return the data to be inserted from the database if there are unknowns to your view (e.g database id). Above I just insert the searchTxt which is what we send in to the function based on what the user typed in the input-field. The choice is yours here.
Get suggestions for previously searched terms
I would start by adding an input field that runs a function on the onKeyPress event:
<input type="text" onKeyPress={this._getSuggestions} />
then the function would be something like:
_getSuggestions = (e) => {
let inputValue = e.target.value;
let {previousQueries} = this.state;
let results = [];
previousQueries.forEach((q) => {
if (q.toString().indexOf(inputValue)>-1) {
result.push(a);
}
}
this.setState({suggestions: results});
}
Then you can output this.state.suggestions somewhere and add behavior there. Perhaps some keyboard navigation or something. There are many different ways to implement how the results are displayed and how you would select one.
Note: I haven't tested the code above
I guess you have somewhere a function that queries the server, such as
const queryServer = function(queryString) {
/* access the server */
}
The trick would be to memorize this core function only, so that your UI thinks its actually accessing the server.
In javascript it is very easy to implement your own memorization decorator, but you could use existing ones. For example, lru-memoize looks popular on npm. You use it this way:
const memoize = require('lru-memoize')
const queryServer_memoized = memoize(100)(queryServer)
This code keeps in memory the last 100 request results. Next, in your code, you call queryServer_memoized instead of queryServer.
You can create a memoization function:
const memo = (callback) => {
// We will save the key-value pairs in the following variable. It will be our cache storage
const cache = new Map();
return (...args) => {
// The key will be used to identify the different arguments combination. Same arguments means same key
const key = JSON.stringify(args);
// If the cache storage has the key we are looking for, return the previously stored value
if (cache.has(key)) return cache.get(key);
// If the key is new, call the function (in this case fetch)
const value = callback(...args);
// And save the new key-value pair to the cache
cache.set(key, value);
return value;
};
};
const memoizedFetch = memo(fetch);
This memo function will act like a key-value cache. If the params (in our case the URL) of the function (fetch) are the same, the function will not be executed. Instead, the previous result will be returned.
So you can just use this memoized version memoizedFetch in your useEffect to make sure network request are not repeated for that particular petition.
For example you can do:
// Place this outside your react element
const memoizedFetchJson = memo((...args) => fetch(...args).then(res => res.json()));
useEffect(() => {
memoizedFetchJson(`https://pokeapi.co/api/v2/pokemon/${pokemon}/`)
.then(response => {
setPokemonData(response);
})
.catch(error => {
console.error(error);
});
}, [pokemon]);
Demo integrated in React

Resources