link1644 link1645 link1646 link1647 link1648 link1649 link1650 link1651 link1652 link1653 link1654 link1655 link1656 link1657 link1658 link1659 link1660 link1661 link1662 link1663 link1664 link1665 link1666 link1667 link1668 link1669 link1670 link1671 link1672 link1673 link1674 link1675 link1676 link1677 link1678 link1679 link1680 link1681 link1682 link1683 link1684 link1685 link1686 link1687 link1688 link1689 link1690 link1691 link1692 link1693 link1694 link1695 link1696 link1697 link1698 link1699 link1700 link1701 link1702 link1703 link1704 link1705 link1706 link1707 link1708 link1709 link1710 link1711 link1712 link1713 link1714 link1715 link1716 link1717 link1718 link1719 link1720 link1721 link1722 link1723 link1724 link1725 link1726 link1727 link1728 link1729 link1730 link1731 link1732 link1733 link1734 link1735 link1736 link1737 link1738 link1739 link1740 link1741 link1742 link1743 link1744 link1745 link1746 link1747 link1748 link1749 link1750 link1751 link1752 link1753 link1754 link1755 link1756 link1757 link1758 link1759 link1760 link1761 link1762 link1763 link1764 link1765 link1766 link1767 link1768 link1769 link1770 link1771 link1772 link1773 link1774 link1775 link1776 link1777 link1778 link1779 link1780

[Vue.js] Break Promise in Vuex Action on API error

This is probably an issue of using the wrong pattern to accomplish what I’m needing, so either an answer of what pattern (and what that pattern is) I should be using or what would solve my current pattern would be greatly appreciated!

there is use case where I need to wait for 1 to many API calls to successfully complete before routing the user to a different page/view… Here’s what I’m doing:

// Vuex action
[POST_NEW_INVOICE_UPDATE]: ({ commit }, update) => {
return apiEndpoints
.postNewInvoiceUpdate(update)
.then(() => {
app.$Progress.finish()
app.$Toastr.success(‘Invoice flagged’)
})
.catch((error) => {
console.error(error)
app.$Progress.fail()
app.$Toastr.error(‘There was an issue submitting the request’, ‘Request error’)
})
},

// In component
flag () {
// … simplifying for TLDR
const promises = []
flagSelections.forEach(selection => {
// … simplifying for TLDR
promises.push(this.$store.dispatch(‘POST_NEW_INVOICE_UPDATE’, parameters))
})

Promise.all(promises)
.then(() => {
// Route to next invoice in previous search, if search exists
// … simplifying for TLDR
})
.catch((error) => {
console.error(error)
})
},

I’m creating an array of the action, POST_NEW_INVOICE_UPDATE, and calling Promise.all on that array. the .then chain to break when an error is caught by the .catch in the action, becuase I don’t want to route my users until the APIs have been successful.

I believe I read in MDN that .then continues to chain even if an error is caught, but I obviously need something to prevent my user from being routed before the APIs are all successful.

I imagine I’m just using a dumb, self-created pattern and am not using Vuex actions correctly, so any help in the right direction would be appreciated!

EDIT: I forgot something important! If I take the code from the action and put it in promises.push instead of the dispatch, the code operates as needed, but I hate breaking the pattern of using Vuex for a single use-case.

Solution :

First off, I wouldn’t use Vuex purely to make API calls. The purpose of Vuex is to manage a global state, and I can see here that you’re not even using commit to mutate the state at all. You can abstract the API into the own objects or functions without needing Vuex. But it’s possible you just trimmed the code down and you actually are calling commit, so I’ll stick with that assumption.

Furthermore, it’s anti-pattern for Vuex to be making calls like app.$Progress.fail(). Vuex should know nothing about the components or UI, its sole job is to manage global state.

Here’s how I would structure it:

async flag() {
const promises = [];

flagSelections.forEach(selection => {
promises.push(postNewInvoiceUpdate(parameters));
});

try {
await Promise.all(promises);
app.$Progress.finish();
app.$Toastr.success(‘Invoice flagged’);
} catch (e) {
console.error(error);
app.$Progress.fail();
app.$Toastr.error(
‘There was an issue submitting the request’,
‘Request error’
);
}
},

If any of the Promises fail, the code in the catch block will be executed. Promise.all means all Promises must resolve, not just some of them. And I would just import postNewInvoiceUpdate from a separate module. There’s no need to use Vuex for this.