lost9123193 lost9123193 - 24 days ago 6
React JSX Question

Nested For Loop not Working With Redux Thunk

I'm having a problem with the flow of redux thunk.

In the action creator, I first create an image object and get the

image_id
from the database.

I have a var called
clients
which is a list of all the client id's that will need the image id. [1,2,3,4,5]

I go through a for loop, fetch the clients using axios.get and I add the new image_id to the list of images from the client field.

Then I put the new changes to the the clients in the field,
client_images
.

export function addNewClient(imageData, clients) {
return function(dispatch) {
axios.post(`${API_URL}/media`, fileData, { withCredentials: true, headers: { 'Content-Type': 'multipart/form-data' } })
.then(response => {
var image_id = response.data.id;

//go through each client to get current background list
for (var i = 0; i < clients.length; i++) {
var currRow = clients[i];
console.log("GETTING NEW CLIENT", currRow)
axios.get(`${API_URL}/clients/${currRow}`, { withCredentials: true })
.then(response => {
var currImages = response.data.client_images;
var clientImages = [...currImages, image_id];
console.log("ADDING NEW CLIENT IMAGE IDs", currRow);
axios.put(`${API_URL}/clients/${currRow}`, {client_images:clientImages}, { withCredentials: true })
})
.catch(() => {
console.log("Can't set image list to clients");

});
}
});
}


}

My problem lies here:
The entire for loop is done before I can call

axios.put(`${API_URL}/clients/${currRow}`, {client_images:clientImages}, { withCredentials: true })


In my console, this is the output

enter image description here

As you can see, Adding New Client Images is only called AFTER the for loop is DONE. I need the "Adding New Client Images" to be called INSIDE the for loop so that the other axios function can be called instead of it being called 5 times to the client with id of 5.

Is there a way to get the for loop working in redux thunk?

Answer

Ah this one is always tricky at first. When using promises with arrays, use array.map instead of a for loop. So try changing this:

for (var i = 0; i < clients.length; i++) {
    var currRow = clients[i];
    axios.get(`${API_URL}/clients/${currRow}`, { withCredentials: true })
    // ...
}

To this:

return Promise.all(clients.map(function(currRow){
    return axios.get(`${API_URL}/clients/${currRow}`, { withCredentials: true })
    // ...
}));

That will make sure all of the promises have their own scope.

So the end result is something like:

export function addNewClient(imageData, clients) {
    return function(dispatch) {
        axios.post(`${API_URL}/media`, fileData, { withCredentials: true, headers: { 'Content-Type': 'multipart/form-data' } })
            .then(response => {
                var image_id = response.data.id;

                //go through each client to get current background list 
                return Promise.all(clients.map(function(currRow){
                    console.log("GETTING NEW CLIENT", currRow)
                    return axios.get(`${API_URL}/clients/${currRow}`, { withCredentials: true })
                        .then(response => {
                            var currImages = response.data.client_images;
                            var clientImages = [...currImages, image_id];
                            console.log("ADDING NEW CLIENT IMAGE IDs", currRow);
                            return axios.put(`${API_URL}/clients/${currRow}`, {client_images:clientImages}, { withCredentials: true })
                        })
                        .catch(() => {
                            console.log("Can't set image list to clients");

                        });
                }));
            });
    }
}