Search code examples
reactjsreduxredux-thunkredux-promise-middleware

Chaining redux payload with axios


I'm building a front-end using React and Redux (with promise middleware and thunk) for a WordPress backend (REST).

Right now I'm doing simple dispatches with Redux to fetch page data, like this one for instance:

export const fetchPostBySlug = (slug) => {
  return {
    type: "FETCH_MODULES",
    payload: axios.get(`${REST_URL}/wp/v2/posts?slug=${slug}`)
  }
}

Now I want to do a more complex call. I want to fetch all tags from WordPress and return these. Then I fetch all featured tags. Then I fetch all posts having a featured tag. Then I fetch all custom post types having a featured tag.

My payload would ideally look like this in the end:

payload: {
  id: 5,
  name: 'tag_5',
  slug: '/tag_5',
  tags: [all tags]
  posts: [all posts and cpt having a featured tag in here together]
}

This is what I have right now which fetches basically fetches everything but doesn't concat and dispatch yet.

const fetchTagPosts = () => {
  axios.all([fetchAllTags(), fetchFeaturedTopics()])
    .then(axios.spread((all, featured) => {
      let payload = {}
      const ft = featured.data.featured_tags
      const ft_length = ft.length

      ft.map((x, i) => {
        getPostsByTag(x.term_id).then(y => payload = addPostToPayload(y.data, x.term_id, payload))
        getCPTByTag(x.term_id).then(y => payload = addPostToPayload(y.data, x.term_id, payload))
        // I need to check here if both are loaded, so I can concat the arrays
        if (ft_length === i + 1) {
          // I need to dispatch/return the payload here
        }
      })
    }))
}

const addPostToPayload = (p, id, payload) => {
  return {
    [id]: {
      posts: payload[id] ? payload[id].posts.concat(p) : p
    }
  }
}

Solution

  • Since you are using thunk, you can return a function that accepts dispatch and use that dispatch to send the payload to the reducer.

    You also don't need the if statement inside the map function, since map will not loop over the array. In fact, using forEach would be more appropriate in this case, since we are not returning anything.

    So your fetchTagPosts would look something like the following:

    const fetchTagPosts = (dispatch) => {
      axios.all([fetchAllTags(), fetchFeaturedTopics()])
        .then(axios.spread((all, featured) => {
          let payload = {}
          const ft = featured.data.featured_tags
          
          // loop through ft
          ft.forEach(x => {
            getPostsByTag(x.term_id).then(y => payload = addPostToPayload(y.data, x.term_id, payload))
            getCPTByTag(x.term_id).then(y => payload = addPostToPayload(y.data, x.term_id, payload))
          });
          
          // dispatch payload to reducer
          dispatch({
            type: 'FETCH_TAG_POSTS',
            payload,
          });
        }))
    }