0

I am building an app. This app needs to request a woocommerce API for product data. The API will only allow 100 items at a time, so I have had to call this request 4 times with dynamic page parameters.

My aim for this data is to have a reducer combine the data into one array that can be filtered in a react component.

My problem at the moment is that my reducer is adding each API call to state in its own array. So rather than have a big array with 300 ish products in, I have 1 array that contains 4 arrays each with 100 products in. Please see the image below.

State data result

Here is the action:

export function fetchJuiceData(page) {
  return dispatch => {
    dispatch(getDataPending("juicedata"));
    return axios
      .get(
        "API_call/end_point/&page=" +
          page
      )
      .then(response => {
        dispatch(getDataSuccess("juicedata", response));
      })
      .catch(err => {
        dispatch(getDataFailure("juicedata", err));
      });
  };
}

Which gets run 4 times with async:

const juiceDataPages = 4;
    var i;
    for (i = 0; i < juiceDataPages; i++) {
      await dispatch(fetchJuiceData(i + 1));
    }

My reducer:

const juiceDataReducer = (state = initState, action) => {
  switch (action.type) {
    case "FETCH_JUICEDATA_PENDING": {
      return { ...state, fetching: true };
    }
    case "FETCH_JUICEDATA_REJECTED": {
      return { ...state, fetching: false, error: action.payload };
    }
    case "FETCH_JUICEDATA_FULFILLED": {
      return {
        ...state,
        fetching: false,
        fetched: true,
        juiceData: [...state.juiceData, action.payload]
      };
    }
    default: {
      return state;
    }
  }
};

I am not the greatest coder in the world and would love your input. I have been banging my head against a wall for days now. TIA.

Laczkó Örs
  • 1,082
  • 1
  • 18
  • 38
  • In your action why not just pass `response.data` as a parameter to your `getDataSuccess` function and once you get all the data flatten that array. – Mohit Garg Sep 26 '19 at 13:34

1 Answers1

1

It seems like the payload you're putting in is an array by itself. So try using the spread operator on it too like so:

case "FETCH_JUICEDATA_FULFILLED": {
  return {
    ...state,
    fetching: false,
    fetched: true,
    juiceData: [...state.juiceData, ...action.payload]
  };
}

This way only the items inside of the payload are added instead of the whole array.

Milan Karman
  • 347
  • 2
  • 8
  • Exacly, `const juiceData = data` is exacly the same as writting `const juiceData = [...data]`, if data is an array. The spread operator allows to **take everything inside**, so `juiceData: [...state.juiceData, ...action.payload]` means `juiceData = [everything inside state.juiceData, everything inside action.payload]` and you have to do this because as @Milan Karman said, the payload is an array by itself. – David Alvarez Sep 26 '19 at 14:47
  • Hi Guys, I have already tried this but i get a TypeError: action.payload is not iterable which returns an empty array. – Ben Edwards Sep 26 '19 at 15:31
  • Ignore that last comment, working from both of the comments, I have passed response.data from the action and then spread the action.payload. This is now working perfectly, thank you all so much. Headache gone. – Ben Edwards Sep 26 '19 at 15:39