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
  };
};

1 Answer 1

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);
      }
    };
Sign up to request clarification or add additional context in comments.

5 Comments

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?
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
But the while loop exits.
Assume you have more to start. hasMore = true; otherwise you aren't even attempting the while loop to change hasMore at all.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.