How to chain actions in ReactJS?

Viewed 215

How to chain actions to get the url of image property when I fetch the post list.

I've made a request that fetch all posts, and it gives me a link for the property "image".

mywebsite/api/recipes?_page=1 :

{
    "@context": "/api/contexts/Recipes",
    "@id": "/api/recipes",
    "@type": "hydra:Collection",
    "hydra:member": [
        {
            "@id": "/api/recipes/524",
            "@type": "Recipes",
            "id": 524,
            "category": "/api/categories/11",
            "title": "NewPost",
            "content": "This is a new post",
            "time": "50 minutes",
            "image": [
                "/api/images/37"
            ],
            "slug": "new-post",
            "createdAt": "2020-06-30T10:26:00+00:00",
            "comments": [
                "/api/comments/1359",
                "/api/comments/1360"
            ]
        },
        ........

and the result for mywebsite/api/images/37 is :

{
    "url": "/images/5efbe9a4a1404818118677.jpg"
}

now in my actions i have

export const recipesListError = (error) => ({
   type: RECIPES_LIST_ERROR,
   error
});

export const recipesListReceived = (data) => ({
   type: RECIPES_LIST_RECEIVED,
   data
});

export const recipesListFetch = (page = 1) => {
   return (dispatch) => {
      dispatch(recipesListRequest());
      return requests.get(`/recipes?_page=${page}`)
         .then(response => dispatch(recipesListReceived(response)))
         .catch(error => dispatch(recipesListError(error)));
   }
};

so the first request is recipesListFetch, now what is missing is the second request to get the image and then return the url so i can directly have access to the image for each post

the easy solution would have been to use normalization_context groups has i'm working with symfony api platform but it still gives me a link for the image property, I think because it's a ManyToMany relation

1 Answers

There don't seem to have the need for normalisation. The images and comments are specific to the recipe.

Make the then block callback as async fun and inside then block loop thru the recipes array first and then loop thru the image array and make api call for the image and await for it.

export const recipesListFetch = (page = 1) => {
  return (dispatch) => {
    dispatch(recipesListRequest());
    return requests
      .get(`/recipes?_page=${page}`)
      .then(async (response) => {
        //make then callback as async fun
        const recipes = response["hydra:member"];
        const imagesForTheRecipie = [];
        for (let i = 0; i < recipes.length; i++) {//loop thru recipies
          for (let j = 0; j < recipes[i].image.length; j++) {//loop thru images for each recipie
            const imageUrl = recipes[i].image[j];//grab the image url
            const image = await requests.get(`/${imageUrl}}`);
            imagesForTheRecipie.push(image);
          }
          recipes[i].image = imagesForTheRecipie; //mutate the object which will directly update the response
        }
        dispatch(recipesListReceived(response));
      })
      .catch((error) => dispatch(recipesListError(error)));
  };
};

Note - If you want to normalise then you can choose to nomalise data for the categories as the same category will be used by many recipes. In that case you will have to re-structure your reducers.

Related