geochanto
geochanto

Reputation: 1002

Axios POST promise not working as expected

I have a react/node/express app with Sequelize/mysql. Using Axios for API calls.

What I need to do:

  1. POST recipe to DB
  2. Wait for the above to complete
  3. GET recipes table again to update the react component state with the new recipe

What currently happens:

  1. recipe gets POSTed to DB
  2. GET recipes gets executed before the promise is returned from the POST. Thus, the component state gets set to old data.

I tried to use async/await but this did not make a difference.

Here's the abridged code:

API.js:

addRecipe: async function(newRecipe) {
    let addRecipe = await axios.post('/api/recipes/new', newRecipe) 
    return addRecipe
},
getRecipes: function() {
    return axios.get('/api/recipes');
}

Recipes.js:

  import API from '../../utils/API';
  state = {
    dbRecipes: []
  }

  getRecipes = () => {
    API.getRecipes()
      .then(res => {
        this.setState({
          dbRecipes: res.data
        })
      })
  }

  handleFormSubmit = event => {
  event.preventDefault();
    API.addRecipe(formData).then(result => {
       this.getRecipes()
    })
  }

addRecipe controller:

exports.addRecipe = function (req, res) {
  const imgPath = req.file.path.replace('client/public','');
  db.Recipe.create({
    RecipeName: req.body.RecipeName,
    RecipeDescription: req.body.RecipeDescription,
    RecipeImage: imgPath
  }).then(function (newRecipe) {
    RecipeIngredients = JSON.parse(req.body.RecipeIngredients)
    var promises = [];
    for (var i = 0; i < RecipeIngredients.length; i++) {
      var RecipeId = newRecipe.dataValues.id;
      promises.push(
        db.RecipeAmount.create({
          Amount: RecipeIngredients[i].AmountForSmall,
          Size: 'sm',
          Type: 'smoothie',
          IngredientId: RecipeIngredients[i].IngredientId,
          RecipeId: RecipeId
        })
      );

      promises.push(
        db.RecipeAmount.create({
          Amount: RecipeIngredients[i].AmountForMedium,
          Size: 'md',
          Type: 'smoothie',
          IngredientId: RecipeIngredients[i].IngredientId,
          RecipeId: RecipeId
        })
      );

      promises.push(
        db.RecipeAmount.create({
          Amount: RecipeIngredients[i].AmountForLarge,
          Size: 'lg',
          Type: 'smoothie',
          IngredientId: RecipeIngredients[i].IngredientId,
          RecipeId: RecipeId
        })
      );
    }

    sequelize.Promise.all(promises).then(function () {
      //this does get logged out in the backend console
      console.log('DONE ADDING');
    });

  });
};

Upvotes: 1

Views: 1531

Answers (1)

Dacre Denny
Dacre Denny

Reputation: 30360

I think the solution is to adjust your addRecipe controller by ensuring that the res call back is called. Seeing that your 'DONE ADDING' message is logged, we can invoke the res callback as follows:

sequelize.Promise.all(promises).then(function () {
      //this does get logged out in the backend console
      console.log('DONE ADDING');

    res.send(); // <-- call the response callback to send a response back 
           // to client only after DB has been updated
});

This should ensure that you're axio post on client-side only completes once the new data is in the DB. In turn this should cause the call to API.getRecipes() to only be invoked once the DB is updated - everything should then work as expected

Upvotes: 1

Related Questions