1

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.

1 Answer 1

7

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();

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! That is really helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.