React findOne returning undefined on Client - reactjs

I'm having problems using findOne because it always returns undefined.
This code:
Routine.js
Meteor.methods({
.... // Some lines missing
'routines.getRoutine'(routineId) {
check(routineId, String);
return Routines.findOne(routineId);
},
});
Note: If I do a console.log of Routines.findOne(routineId) it correctly shows the element that i'm looking for.
App.jsx
handleSubmit(event) {
event.preventDefault();
const comment = ReactDOM.findDOMNode(this.refs.comment).value.trim();
Meteor.call('routines.addComment', this.state.routine._id, comment);
let a = Meteor.call('routines.getRoutine', this.state.routine._id);
ReactDOM.findDOMNode(this.refs.comment).value = '';
this.setState({
routine: a,
});
}
In my Appjs doesn't matter how I try 'a' is always undefined, what am I doing wrong?
Thanks for the help in advance!

I'm pretty sure your problem is that Meteor calls on the client are async and so the method you're calling hasn't completed by the time you're querying the same data.
Try putting the rest of the code in the callback like so:
handleSubmit(event) {
event.preventDefault();
const comment = ReactDOM.findDOMNode(this.refs.comment).value.trim();
Meteor.call('routines.addComment', this.state.routine._id, comment, function() {
let a = Meteor.call('routines.getRoutine', this.state.routine._id);
ReactDOM.findDOMNode(this.refs.comment).value = '';
this.setState({
routine: a,
});
});
}

Related

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).

React js Axios Get Request in submit form

i have a simple input form where i put a list of strings , then for each element of the string (string[i]) i run an ajax Get request to my api .
so here is the ajax request :
async function getUsers(props){
try{
const response = await Axios.get(`url=`+props)
console.log(response)
return response;
}catch{
console.log("response failed")
}
}
and i run it here :
... some code here ...
for(var i =0; i < string.length; i++){ // map the entery (string)
getUsers(string[i]).then(res => {
this.setState({
string2:res // this one is just for testing
});
console.log(res.data.id);
mystring22.push({res});
console.log("me inside the promise : " + this.state.string2.data.id);
})
setTimeout(() => {
console.log("iam not empty " + this.state.string2.data.id);
console.log(mystring22);
/* -----------------
I WANT TO DO SOME WORK HERE
-----------------*/
}, 3000);
this.setState({
string3 : mystring22
})
... some code here ...
so everything works fine , and my problem is the following :
the code take too much time (3 second for each request ) , is there is a way to change the code so it can do "SOMETHING" after each request , i tried to delete the setTimeout or reduce it but that not working the array is undefined after that .
hope you can help me .
thank you
setState is an async function, so when you call:
setState({ string2: res });
this.state.string2; // OUTDATED
in order to access the updated value, you must use the callback:
setState({ string2: res },
() => { console.log(this.state.string2) }); // UP TO DATE
as you can see in this codesandbox example, with the callback on line 27 and without the callback on 33.

setState() causes state variable to be undefined

I am, for the most part, following this tutorial.
My Django API's set up well. I have this service function:
export default class GoalService{
getGoals() {
const url = `${API_URL}/api/goals`;
return axios.get(url).then(response => response.data);
}
}
Which is called by the componentDidMount method in my GoalList:
class GoalTable extends Component {
constructor(props) {
super(props);
this.state = {
goals: [],
now: now.getDate(),
}
}
componentDidMount() {
var self = this;
goalService.getGoals().then(function (result) {
console.log(result);
self.setState({ goals: result.data })
});
}
render() { ... }
(This is step 8 of the above-linked tutorial).
Now, when I try to use { this.state.goals.map(...) }, I get the error TypeError: this.state.goals is undefined. Looking at other threads, a lot of people seem to have had this problem—but it comes about because they've used setState() outside of the request being made and, since setState() is asynchronous, the state is set to something blank. I'm using it inside of a call to then, so I don't think that's the issue.
I tried adding a second argument to then (in case this operation wasn't successful), but, the getGoals() call is successful, and successfully prints out the JSON sent back by Django's API. Similarly, I can see that the request went as expected in the Network tab of the developer tools.
What could be going wrong here? Why isn't the state properly updating w/ the returned JSON?
As mentioned in the comments, the tutorial has a typo, which means that the code tries to access response.data.data instead of response.data.
The fix would be to remove this extra level of drilling down into the object:
componentDidMount() {
var self = this;
goalService.getGoals().then(function (result) {
self.setState({ goals: result }) // no .data
});
}
Also, note that you could make this code simpler by using arrow functions (which automatically bind the this from the place that they're defined) and the object initialization shorthand:
componentDidMount() {
// { goals } is the same as { goals: goals }
goalService.getGoals().then(goals => this.setState({ goals }));
}

How does Meteor methods return results?

I am using meteor/react for learning facebook graph api.
I want to access users' post on facebook timeline and display them on screen. How can that be done?
With the guidance of the solution provided here [How to perform common FB actions using Meteor?. I have tried the following code: server.js
Meteor.methods({
'seePost' : function(){
var graph=Npm.require('fbgraph');
if(Meteor.user().services.facebook.accessToken){
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
var future = new Future();
var onComplete = future.resolver();
graph.get('/me/feed',function(err,result) {
console.log(result);
return onComplete(err,result);
})
Future.wait(future);
}
else{
return false;
}
}
});
client side code :
Meteor.call("seePost", function(err,result) {
if(err) console.log("error" , err);
else console.log("RES", result);
});
I expect the result displayed in the client side console since I want to show the users the posts on his/er timeline, But I get following output :
RES, undefined
You can do it using await and Meteor.callAsync
Basically the client code waits for the call to complete, and gives you the returned data
const result = await Meteor.callAsync("seePost");
Errors should be handled with a try..catch block
If you use fibers/future, you need to return something with "future".
const future = new Future();
// some code getting result or something
future.return(something);
return future.wait();
this will return something in the callback from client call.
try this code, when you're using fibers you need to "wait" for the response
Meteor.methods({
'seePost': function () {
var graph = Npm.require('fbgraph');
if (Meteor.user().services.facebook.accessToken) {
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
var future = new Future();
var onComplete = future.resolver();
graph.get('/me/feed', function (err, result) {
console.log(result);
if (err) {
return future.return(false);
} else {
return future.return(result);
}
})
return future.wait();
}
return false;
}
});

call on function returns undefined on first call

In my controller i am calling this function in my service. idservice.getid()
I am testing it by printing it to console using console.log(idservice.getid())
and it returns undefined the first time, but after that if i call it again it returns the value.
I understand this is a async issue but im not sure how to make this work.
my service is below:
function idservice (userauth) {
var id;
this.getid = function() {
userauth.currentUser().then(function(user) {
id = user.id;
});
return id
}
}
How can i make it so that on the first call it doesnt return undefined? Is this a async issue?
This's happening because inside userauth currentUser() method you're making http call and response ('user.id') is yet not available. You can return the userauth.currentUser() call inside getid() method & also return id inside its success callback then. So your service method should look like
function idservice (userauth) {
var id;
this.getid = function() {
return userauth.currentUser().then(function(user) {
id = user.id;
return id;
});
}
}
And inside controller you should handle it like
idservice.getid().then(function(response){
$scope.id = response;
});
Here's small example of your requirement: https://plnkr.co/edit/bEjR9e179aRPfJiaQpei?p=preview
I've encountered this problem today, seems like if you request some data from the server and you assign it to a variable THEN you try to print it, it will show undefined on the first call, I think this is not something it should happen since you are trying to print it AFTER you got the information, but whatever.
I fixed it by removing that variable, just got the data then printed it.
I think this will solve your problem (the OP's last login is 2 years ago, but maybe it will help somebody else that encountered this and didn't found a useful answer?)
function idservice (userauth) {
this.getid = function() {
return userauth.currentUser().then(function(user) {
return user.id;
});
}
}
This will return the user.id as it is, it will not store it in a variable, you want it to be stored in a variable ? Store it, but don't print that variable, something like this :
function idservice (userauth) {
var id;
this.getid = function() {
return userauth.currentUser().then(function(user) {
id = user.id;
return user.id;
});
}
}
This worked for me (or at least the logic behind it worked).

Resources