mgs
mgs

Reputation: 67

How to fetch data from MySQL after POST completes

When the user clicks a button, I want the app to

The problem I'm seeing is that pulling down all rows doesn't include the one that was just posted unless I include a manual delay (via setTimeout).

This is what my 2 functions look like

// gets all data, updates state, thus triggering react to rerender
  listWords() {
    setTimeout(() => fetch("http://localhost:9000/listWords")
      .then(res => res.text())
      .then(res => this.setState({ wordList: JSON.parse(res)})), 2000)
  }


// sends new word to the MySQL database, then kicks off the listWords process to refetch all data
addWord() {
    fetch("http://localhost:9000/addWord", {
      method: 'POST',
      headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        word: this.state.newWord
      })
    })
    .then(res => res.json())
    .then(this.listWords())
      
  }

I shouldn't have to have that setTimeout in there, but when I remove it, the listWords update doesn't have the newly posted row.

My best guess is that either

  1. I'm messing up the promise .then() paradigm, or
  2. MySQL responds to my POST request but doesn't actually add the row until the GET has already completed, thereby missing out on the new row.

How can I ensure the POST has successfully completed before I pull the rows again?

I am using react, express, sequelize, and for the DB it's MySQL in a docker container.

Upvotes: 2

Views: 1006

Answers (1)

JensV
JensV

Reputation: 4544

You indeed made a mistake, a common trap which I myself fell into as well a few times :)

When calling addWord() it will evaluate then(this.listWords()). This will immediately call listWords().

Instead you pass a function to then(...) (instead of calling a function) for example like this:

.then(() => this.listWords())

or even like this:

.then(this.listWords)

Now, instead of passing the result of listWords() to then() it will pass a function that will call listWords() to then() thus only executing listWords() when the Promise reaches this then()


Example to make this behavior even clearer:

When calling a function function foo(arg1) {}, JS needs to know the value of arg1 before calling foo. Let's take the following piece of code:

foo(bar())

In this case, bar() must be called before foo(...) because the arg1 will be the returned value of bar(). In constrast to the following case:

foo(() => bar())

Now, arg1 will be a function instead of the returned value of bar(). This is equivalent to:

var arg = () => bar();
foo(arg);

In contrast to:

var arg = bar();
foo(arg);

Where it is obvious what will happen.

In chained functions like foo(arg1).bar(arg2).baz(arg3), all args will be evaluated before calling foo(...).


Some help to debug such problems: Use the Network Inspector in your browser. It will show the order of requests performed and in this example you would have seen that the GET request was actually performed before the POST request. This might not explain why it happens but you can understand the problem faster.

Upvotes: 2

Related Questions