6

I'm getting the error "Redux Actions must be plain objects. Use custom middleware for async action." with the below code.

export const getFriends = () => async(): Action => {

  const requestConfig = {
    httpMethod: 'GET',
    version: 'v2.7',
  };
  let hasMore = false;
  let friends = [];

  do {
    const infoRequest = new GraphRequest(
    '/me/friends',
    requestConfig,
    (error, result) => {
      if (error) {
        alert('Error fetching data facebook friends');
      } else {
        result.data.forEach((value) => {
            friends.push(value)
        });
        if (result.paging && result.paging.next) {
          hasMore = true;
          requestConfig.parameters.after = result.paging.cursors.after;
        } else {
          hasMore = false;
        }
      }
    });
    await new GraphRequestManager().addRequest(infoRequest).start();
  } while (hasMore);
  return {
    type: 'GET_FRIENDS',
    payload: friends    // this is empty because there is no await on GraphAPI
  };
};

If I remove the async and await, the friend returned is empty because function call returned before GraphAPI call returned

export const getFriends = () => (): Action => {

  const requestConfig = {
    httpMethod: 'GET',
    version: 'v2.7',
  };
  let hasMore = false;
  let friends = [];

  do {
    const infoRequest = new GraphRequest(
    '/me/friends',
    requestConfig,
    (error, result) => {
      if (error) {
        alert('Error fetching data facebook friends');
      } else {
        result.data.forEach((value) => {
            friends.push(value)
        });
        if (result.paging && result.paging.next) {
          hasMore = true;
          requestConfig.parameters.after = result.paging.cursors.after;
        } else {
          hasMore = false;
        }
      }
    });
    new GraphRequestManager().addRequest(infoRequest).start();
  } while (hasMore);
  return {
    type: 'GET_FRIENDS',
    payload: friends    // this is empty because there is no await on GraphAPI
  };
};
user43286
  • 2,261
  • 3
  • 31
  • 42

1 Answers1

2

The error means exactly what it sounds like. Redux is expecting a plain object. I see the question tagged with redux-thunk. If you are using redux-thunk, perhaps you don't have the store set up with the middleware properly. If you aren't using redux-thunk then I would recommend it as the go-to library for dispatching async actions.

This will give you great insight about dispatching redux actions that aren't plain objects. How to dispatch a Redux action with a timeout?

edit: You are missing the actual dispatch and are trying to simply return plain object... need to return a dispatch... something like the following (haven't testing, but should get you close):

    export const getFriends = () => {
      return (dispatch) => {
        const requestConfig = {
          httpMethod: 'GET',
          version: 'v2.7',
        };
        let hasMore = false;
        let friends = [];

        do {
          const infoRequest = new GraphRequest(
            '/me/friends',
            requestConfig,
            (error, result) => {
              if (error) {
                alert('Error fetching data facebook friends');
              } else {
                result.data.forEach((value) => {
                    friends.push(value)
                });
                if (result.paging && result.paging.next) {
                  hasMore = true;
                  requestConfig.parameters.after = result.paging.cursors.after;
                } else {
                  hasMore = false;
                  return dispatch({
                    type: 'GET_FRIENDS',
                    payload: friends               
                  });
                }
              }
          });
          await new GraphRequestManager().addRequest(infoRequest).start();
        } while (hasMore);
      }
    };
Community
  • 1
  • 1
Travis White
  • 1,977
  • 1
  • 11
  • 19
  • Yes, I'm using redux-thunk. See my do while. I need to await because of do while. The GraphAPI won't return entire return in one shot, so I have to paginate. How do I do that? – user43286 Dec 15 '16 at 22:03
  • To follow up on that code snippet, redux-thunk is great in that you can dispatch multiple events from same action. So you could dispatch an event to signal the start of the loading process and then dispatch ADD_FRIENDS method each time the data is received instead of waiting until the end. Don't need to return anything, you just needed to actually dispatch() the plain object actions when neccessary – Travis White Dec 15 '16 at 22:34
  • But the while loop exits. – user43286 Dec 15 '16 at 23:14
  • Assume you have more to start. hasMore = true; otherwise you aren't even attempting the while loop to change hasMore at all. – Travis White Dec 15 '16 at 23:18
  • The problem is because of the async GraphRequestManager. On the first do while iteration you are awaiting to start the GraphRequestManager. The await isn't waiting for a GraphRequest data callback, just getting the request started. So the callback probably hasn't had time to fire to even attempt to modify/update hasMore. You can add some console.logs in the callback and in while loop (outside of defining the infoRequest) to confirm or deny this. – Travis White Dec 15 '16 at 23:30