Fetch console showing value but cant save it to a variable - javascript

This is what I have .
var a;
handleSubmit(event) {
var a ;
event.preventDefault();
this.setState({username:'poop'})
console.log("submit");
fetch('http://localhost:8080/login/'+this.state.username+'/'+this.state.password,{
method: 'GET',
}).then((resp)=> resp.text())
.then(resp => {
console.log(resp)
a = resp;
});
console.log(a);
My issue is that the console.log(resp) will log the correct value I need ("Success") but when I try to do var a = resp it shows up as undefined. my api returns 1 string , either success or fail. the log will show success but for some reason I can not get it assigned to a variable.

You are making an asynchronous request within handleSubmit and hence you won't get the result immediately after fetch Request in the manner you are trying to access it, you can store the result in state using setState and access it elsewhere with this.state.data
handleSubmit(event) {
event.preventDefault();
this.setState({username:'poop'})
console.log("submit");
fetch('http://localhost:8080/login/'+this.state.username+'/'+this.state.password,{
method: 'GET',
}).then((resp)=> resp.text())
.then(resp => {
console.log(resp)
this.setState({data: resp});
});
}
Alternatively you can make use of async-await like
async handleSubmit(event) {
event.preventDefault();
this.setState({username:'poop'})
console.log("submit");
const a = await fetch('http://localhost:8080/login/'+this.state.username+'/'+this.state.password,{
method: 'GET',
}).then((resp)=> resp.text())
console.log(a);
}

Related

React.js Trying to access the response of an API fetch that works and returns data in my /api but I cannot access in my /src/

I think I am probably missing something pretty simple.
in src/api/index.js I have the following:
export async function loginUser(username, password) {
try {
const response = await fetch(`${BASE}/users/login`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user: {
username: username,
password: password
}
})
})
.then(response => response.json())
.then(result => {console.log(result)
const key = result.data.token
localStorage.setItem('stToken', JSON.stringify(key))
localStorage.setItem('username', JSON.stringify(username))
})
return response
} catch (error) {
console.log(error);
}
}
My loginUser is being called in my onSubmit handler in my src/component/login.js
const submitHandler = async (event) => {
event.preventDefault()
setUserData( {username, password})
const response = await loginUser(username, password)
alert({response})
console.log(response.data)
}
This API call returns from the loginUser function, when called by onSubmit:
{success: true, error: null, data: {…}}
data: {token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2M…TU2fQ.4l7g5y8hlEDxlmkWUPiVIfM6XWCqHa0410QXGLy72vw', message: 'Thanks for logging in to our service.'}
error: null
success: true
[[Prototype]]: Object
However, whatever I try to access the return data from the submitHandler (such as console.log or any variation of response.data.token I try, I just get null. As of right now the only way for me to access any API returns in my API folder are via local storage.
Please help me identify what i am missing.
First of all, you are using both promises (.then) and async await.
When you await the fetch.then.then you actually awaits for the last returned value. In your case, since you return nothing (undefined) from your last .then, you can't access the data.
Try return the result -
const response = await fetch(`${BASE}/users/login`, {...})
.then(response => response.json())
.then(result => {console.log(result)
const key = result.data.token
localStorage.setItem('stToken', JSON.stringify(key))
localStorage.setItem('username', JSON.stringify(username))
return result; // this is the line I added
})

How do I nest callbacks for async functions in javascript? [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I've looked but haven't been able to find a solution to this specific problem, so I thought I'd ask. I'm a novice javascript developer who clearly needs to read more about scope, callbacks and promises.
I'm trying to nest callbacks to get data out of a http request using the fetch API in javascript. At this point in my project, I've sent data to a node back end, called a few apis, then sent json data back to the client.
I now want to access that data outside of the function getServerData in the below.
I've tried a few different things but haven't been able to figure it out. I feel like I'm missing something obvious.
My current code is below:
//I want to access callback data here
const getServerData = userData => {
// declare data to send
const apiData = userData;
// declare route
const url = 'http://localhost:3030/nodeserver';
// declare POST request options
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(apiData)
};
// Async function to fetch from Node server w/ callback
const fetchUIData = async callback => {
await fetch(url, options)
.then(response => response.json())
.then(data => {
callback(data);
})
.catch(err =>
console.log(
`There was an error fetching from the API POST route:${err}`
)
);
};
// Variable to store callback data
let serverData = [];
// Callback function to use data from fetch
return fetchUIData(data => {
serverData = data;
console.log(serverData);
});
};
You don't nest callbacks when using await. The whole point of await is to get rid of the .then( .then( .then())) callback hell and nesting. Either use .then() (if you enjoy callback hells :) or await; not both together, it doesn't make sense.
const getServerData = async userData => {
const url = 'http://localhost:3030/nodeserver';
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData)
};
const response = await fetch(url, options);
return response.json()
};
const serverData = await getServerData(userData);
console.log(serverData); // <-- Tadaaa
As soon as the result is based on some asynchronous work, you need to return it using a Promise or a callback.
So const getServerData = userData => { has to either accept a callback, or to return a Promise.
The callback in that part of your code does not seem to have any purpose:
return fetchUIData(data => {
serverData = data;
console.log(serverData);
});
It seems as if you just want to return data from getServerData
So also that part does not make any sense:
.then(data => {
callback(data);
})
So the code could look like this:
const getServerData = userData => {
// declare data to send
const apiData = userData;
// declare route
const url = 'http://localhost:3030/nodeserver';
// declare POST request options
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(apiData)
};
// Async function to fetch from Node server w/ callback
const fetchUIData = () => {
return fetch(url, options)
.then(response => response.json())
.catch(err =>
console.log(
`There was an error fetching from the API POST route:${err}`
)
return null;
);
};
// Callback function to use data from fetch
return fetchUIData()
};
But even that could be simplified:
const getServerData = async userData => {
// declare data to send
const apiData = userData;
// declare route
const url = 'http://localhost:3030/nodeserver';
// declare POST request options
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(apiData)
};
// fetch from Node server
try {
let response = await fetch(url, options)
return response.json()
} catch( err ) {
console.log(
`There was an error fetching from the API POST route:${err}`
)
return null;
}
};
The whole try-catch block is probably also something you want to remove, letting the error propagate. In the current form, the getServerData will always fulfill and only log the error. That's in many cases not what you want. But that depends on the exact use case.
The function is then used that way:
let data = await getServerData();

how to access variables inside Fetch returned value

I have a products page with a button (addToCart) and I use fetch to add the product to req.session.cart on the server. On the front of the app, I use fetch to communicate with the server and get the req.session.cart as a returned value. How to assign the fetch results to an outside variable?
let whatevervariablehere
function addToCart(e){
let items = e.target.parentElement.parentElement
// rest of the clicked item code .....
//fetch and send the data to server so you can update session
fetch('sc8', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify({
title : title,
price : price,
description : description,
id : id
})
}).then(response => response.json()).then((results) => {
//**this is the part I'm talking about**
console.log("|||||results|||||", results)
//**How to get access to "retrievelocalstorage" from outside of this code**
localstorage = window.localStorage.setItem(JSON.stringify(user), JSON.stringify(results));
retrievelocalstorage = JSON.parse(window.localStorage.getItem(JSON.stringify(user))) || "No items in cart, Yet!";
// the below console.log prints the right results
console.log("retrievelocalstorage", retrievelocalstorage)
}) //results function end
.catch(error => console.log(error));
} //end of addTocart Function
// this prints "outside the addToCart" and nothing else.
// it is outside the addToCart fn and the fetch promise.
// can I have access to retrievelocalstorage value out here, out of the
// function and the promise or not?
**console.log("this is outside the addToCart fn", retrievelocalstorage)**
IS it possible to get access to retrievelocalstorage out side of the results fn?
Edit 1
The console.log("this is outside the addToCart fn", retrievelocalstorage) doesn't print the value of retrievelocalstorage. so the suggestion to add .then(retrievelocalstorage => whatevervariablehere = retrievelocalstorage) is still showing whatevervariable empty in consolelog.
You can try to use async/await here so that you don't use .then and can assign the result to a variable.
async function getResults() {
const result = await fetch(...).json() // your code for fetch
// work with result as a regular variable
}
You are in the async context. You should continue working inside the promise:
.then(() => {
// you can get your data from LocalStorage here
})
The code after fetch works without awaiting results
Or you can wrap async fn to another fn and use async/await
async function() {
await addToCart...
// you can get your data from LocalStorage here
}

Function does not wait for fetch request

I am trying to retrieve JSON from a server as an initial state.
But it looks like the function doesn't wait for the response.
I looked at different Stackoverflow posts like How to return return from a promise callback with fetch? but the answers I found didn't seem to help.
// Get the best initial state available
// 1. Check for local storage
// 2. Use hardcoded state with the test value from the server.
export function getInitialState() {
if (localStorage.getItem('Backup') != undefined) {
return returnValue = Map(JSON.parse(localStorage.getItem('Backup')))
} else {
var returnValue = initialState
const GetJSON = (url) => {
let myHeaders = new Headers();
let options = {
method: 'GET',
headers: myHeaders,
mode: 'cors'
};
return fetch(url, options).then(response => response.json());
};
GetJSON('https://example.com/api/v1/endpoint/valid/').then(result => {
// Console.log gives a good result
console.log(result)
// The return is undefined
return returnValue.setIn(['test'], result)
});
}
}
In this case, I receive an undefined while I expect a returnValue JSON where the test property is updated from the server.
So I really want the function getInitialState() to return the state. And to do this it needs to wait for the fetch to finish. I also tried to place return before the GetJSON but this had no effect.
Oke, so I just tried the following:
GetJSON('https://example.com/api/v1/endpoint/valid/').then(result => {
console.log('aaa')
console.log(result)
localstorage.setItem('init', result)
console.log('bbb')
}).then(result => {
console.log('done')
});
This returns aaa and result.
But the localStorage is never set, and the bbb and done are never shown.

ReactJS: How to rerender component after fetching data

So I have a component which displays some data fetched from an external API and saved to localStorage. I have put a fetchData() function that does the job, and I call this function from within componentWillMount(). It looks like this:
componentWillMount() {
this.fetchData();
}
...
fetchData() {
if(localStorage.myData === undefined) {
fetch(apiUrl,{
method: 'GET',
headers: ...
})
.then(function(data) {
localStorage.setItem('myData', data);
}).catch(function(error) {
// error handling
})
} else { return true; }
}
The idea here is to check on every render if the data is set in localStorage, otherwise fetch it, save data and then rerender. However, I can't get it to rerender after the data is stored in localStorage. I have tried using this.setState({data: data}) instead in the fetchData function, but this is undefined.
What am I doing wrong here? Thank's in advance.
this in your class has a different context than the this inside of your then() function. For your particular case, you can do the following
fetch(apiUrl,{
method: 'GET',
headers: ...
})
.then(function(data) {
// This now refers to your component
this.setState({data: data});
}.bind(this))
.catch(function(error) {
// error handling
})
Or as Utro suggested, you can use arrow functions that will not create their own context thus allowing you to use this appropriately.
fetch(apiUrl,{
method: 'GET',
headers: ...
})
.then(data => {
// This now refers to your component
this.setState({data: data});
}).catch(function(error) {
// error handling
})
This object inside .then will refer to object of Promise call not the object of Component.
vat that = this;
declare some variable of this to that and then you can use
that.setState({})

Categories

Resources