I am sending a HTTP request using Axios inside an asynchronous action creator. The arguments I want to use to call the synchronous action creator are stored in an array. For some reason, when I try to console.log(args)
(the array), I get the array displayed correctly, but when I try to console.log(args[0])
(the first element), I get undefined. I don't know what this issue is linked to. Here is my code snippet:
const initIngredients_Sync = (ingredientsData, error) => {
console.log("sync args", ingredientsData, error);
return({
type: actionTypes.INIT_INGREDIENTS,
initialState: ingredientsData,
error
});
};
export const initIngredients = () => {
const args = [];
return dispatch => {
axiosInstance.get('/ingredients_prices.json')
.then((response) => {
const INGREDIENT_PRICES = response.data;
const INGREDIENTS = (() => {
let ingredients = {};
for (const key in INGREDIENT_PRICES) {
if(key !== "base_price")
ingredients[key] = 0;
}
return ingredients;
})();
const ingredientsData = {
ingredients_prices: INGREDIENT_PRICES,
ingredients: INGREDIENTS,
totalPrice: INGREDIENT_PRICES.base_price
};
args.push(JSON.parse(JSON.stringify(ingredientsData)));
})
.catch((error) => {
args.push(error);
});
console.log("args[0]", args[0]);
args.length === 2
? dispatch(initIngredients_Sync(args[0], args[1])) // [ingredientsData, error]
: dispatch(initIngredients_Sync(args[0], false)); // no error
}
};
Output with console.log(args)
:
[]
0: {ingredients_prices: {...}, ingredients: {...}, totalPrice: {...}}
length: 1
Output with console.log(args[0])
:
undefined
Axios is a promise based HTTP client for the browser and Node.js.
So its methods like .get()
will resolve asynchronously.
An asynchronous model allows multiple things to happen at the same time. When you start an action, your program continues to run. When the action finishes, the program is informed and gets access to the result (for example, the data read from disk).
Resource - https://eloquentjavascript.net/11_async.html
That's why your console.log
does not output the result as you expect. You can fix this by dispatching actions with args
in then
method.
const initIngredients_Sync = (ingredientsData, error) => {
console.log("sync args", ingredientsData, error);
return {
type: actionTypes.INIT_INGREDIENTS,
initialState: ingredientsData,
error,
};
};
export const initIngredients = () => {
const args = [];
return (dispatch) => {
axiosInstance
.get("/ingredients_prices.json")
.then((response) => {
const INGREDIENT_PRICES = response.data;
const INGREDIENTS = (() => {
let ingredients = {};
for (const key in INGREDIENT_PRICES) {
if (key !== "base_price") ingredients[key] = 0;
}
return ingredients;
})();
const ingredientsData = {
ingredients_prices: INGREDIENT_PRICES,
ingredients: INGREDIENTS,
totalPrice: INGREDIENT_PRICES.base_price,
};
args.push(JSON.parse(JSON.stringify(ingredientsData)));
// These lines moved to `then` method
console.log("args[0]", args[0]);
args.length === 2
? dispatch(initIngredients_Sync(args[0], args[1]))
: dispatch(initIngredients_Sync(args[0], false));
})
.catch((error) => {
args.push(error);
});
};
};