Reputation: 8414
I'm having a little trouble dealing with some Promises in my app, any clarification would be much appreciated.
I've been building a Phoenix/React app loosely based on this tutorial - https://medium.com/@benhansen/lets-build-a-slack-clone-with-elixir-phoenix-and-react-part-3-frontend-authentication-373e0a713e9e - and I'm trying to restructure my code a bit to make it easier for me to build out other aspects of the app in the future.
Initially, when posting login data to my Phoenix server, the function that I was using looked like this (from Login.jsx
):
fetch(`${apiUrl}/sessions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({person: person})
}).then(response => {
this.setState({loadingData: false}, () => {
response.json().then(result => {
if(result.status === "error"){
this.setState({error: {isError: true, message: result.message}}, () => {
return;
})
}
else{
this.login(result) //DO SOME OTHER STUFF WITH THE RESULT
}
})
})
}).catch(error => {
console.error("There was an error: " + error);
});
and this worked just fine.
However, I have since restructured my code so that the fetch functionality has been moved into another file. Here's how it looks now (somewhat similar to the tutorial):
fetch.js
let parseResponse = (response) => {
return response.json().then((json) => {
if (!response.ok){
return Promise.reject(json)
}
return json;
});
}
let fetchFunctions = {
post: (url, data) => {
const body = JSON.stringify(data)
fetch(`${apiUrl}${url}`, {
method: 'POST',
headers: headers(),
body: body
})
.then(parseResponse)
}
}
export default fetchFunctions;
Login.jsx
post('/sessions', {person: person})
.then((result) => {
this.login(result) //HERE'S THAT LOGIN FUNCTION I WANT TO RUN
})
Now when I run this, you may not be surprised to learn that I get the error Uncaught TypeError: Cannot read property 'then' of undefined
, and I get it, I think... please correct me if I'm wrong, but the reason that this doesn't work is because fetch()
is a Promise, but I have now wrapped it inside of a function that is not a Promise.
If I add console.log(json)
before the return
statement in parseResponse()
, I do see my data and it looks good... but how can I get that data out of the Promise and into my component? It seems to me that I need to defined post()
as a Promise as well, but I'm not sure how to structure this.
Upvotes: 1
Views: 11028
Reputation: 816432
but the reason that this doesn't work is because fetch() is a Promise, but I have now wrapped it inside of a function that is not a Promise.
Functions are not promises. Functions can return promises. You simply forgot to return the result of fetch
, which is a promise, from post
:
let fetchFunctions = {
post: (url, data) => {
const body = JSON.stringify(data)
return fetch(`${apiUrl}${url}`, {
// ^^^^^^
method: 'POST',
headers: headers(),
body: body
})
.then(parseResponse)
}
}
Now post
returns a promises as well.
If you don't return, the implicit return value will be undefined
, hence the error message "Uncaught TypeError: Cannot read property 'then' of undefined"
Simplest repro case for this error:
function foo(){}
foo().then();
Upvotes: 7