I encountered an issue while using Redux in my React component. Initially, I was trying to dispatch an action and then immediately dispatch another one afterwards.
Here's the original code snippet:
const onClickBtn = () => {
dispatch(addProductStockAndPrices({
productId: itemId,
stockData,
}));
dispatch(getProductById(itemId));
}
However, this approach didn't work as expected. Later, I tried a different approach and it resolved the issue:
const onClickBtn = () => {
dispatch(addProductStockAndPrices({
productId: itemId,
stockData,
}))
.finally(() => {
console.log("finished addProductStockAndPrices");
dispatch(getProductById(itemId));
});
}
Can someone explain why the first approach didn't work while the second one did? I'm using React, Zod, React-Hook-Form, and Redux-Toolkit. Any insights would be appreciated.
Since you tagged redux-toolkit I will assume that the addProductStockAndPrices
action is an asynchronous action since it appears to return a Promise, e.g. createAsyncThunk
.
First Example:
const onClickBtn = () => { dispatch( addProductStockAndPrices({ productId: itemId, stockData, }) ); dispatch(getProductById(itemId)); }
In the first example you are dispatching two actions synchronously, i.e. one right after the other, and when the first action's asynchronous logic completes is irrelevant to the second action, the callback function didn't wait for it to complete before dispatching the second action.
Second Example:
const onClickBtn = () => { dispatch( addProductStockAndPrices({ productId: itemId, stockData, }) ).finally(() => { console.log("finished addProductStockAndPrices"); dispatch(getProductById(itemId)); }); }
The second example's code works because the finally
block of a Promise chain runs at the end of the chain, after all promises in the chain have either resolved or rejected. In other words, the first action's asynchronous logic had to have completed and resolved or rejected prior to the second action being dispatched.
All Redux-Toolkit Thunks will actually always resolve, so if the success of the first action matters at all to the second you will want to unwrap the result of the first. See Handling Thunk Results for details.
Using Promise chain
const onClickBtn = () => {
const payload = { productId: itemId, stockData };
dispatch(addProductStockAndPrices(payload))
.unwrap()
.then((result) => {
// addProductStockAndPrices success
dispatch(getProductById(itemId));
})
.catch(error => {
// addProductStockAndPrices failure
});
}
Using async/await
+ try/catch
const onClickBtn = async () => {
const payload = { productId: itemId, stockData };
try {
const result = await dispatch(addProductStockAndPrices(payload).unwrap();
// addProductStockAndPrices success
dispatch(getProductById(itemId));
} catch(error) {
// addProductStockAndPrices failure
}
}