0

I have the following action in my actions.js file. But I get the error "Actions must be plain objects. Use custom middleware for async actions." I'm assuming it's because I putting the return in a weird place. Any ideas?

export function loginLookUp(credentials) {
  const request = axios.post(`${LOGINLOOKUP_URL}`, credentials).then(function (response) {

      return {
          type: LOGIN_SUCCESS,
          payload: true
      };


  })
  .catch(function (error) {

      return {
          type: LOGIN_FAIL,
          payload: false
      };


  });


}
6
  • 1
    Your action creator doesn't return anything - your return statements are in the scope of the promise callbacks, not the surrounding function. In order to do asynchronous actions, you need to use a library such as redux-thunk or redux-promise. Commented Nov 14, 2016 at 16:04
  • Yes I've been hearing about these but do you have an example as to how the action will look if I use redux-promise for example? Commented Nov 14, 2016 at 16:06
  • I'll write an answer - give me a few minutes :) Commented Nov 14, 2016 at 16:08
  • Thank you :) I can't find that many resources to learn about async actions :) Commented Nov 14, 2016 at 16:09
  • The redux docs give a pretty good introduction into async actions. Did you check it out? Commented Nov 14, 2016 at 16:24

1 Answer 1

1

Your action creator doesn't return anything - your return statements are in the scope of the promise callbacks, not the surrounding function. But that's kind of beside the point - even if you did return the promise from the action creator, Redux wouldn't know what to do with it!

In order to do asynchronous actions, you need to use a library such as redux-thunk or redux-promise. I'm not going to go into detail on how to set these libraries up, as the READMEs on their repos do a much better job, but here's a few examples of how you'd use them.

redux-thunk allows you to dispatch a function that in turn has access to dispatch, like so:

export function loginLookUp(credentials) {
    // This would look a lot cleaner if you used an ES2015 arrow function
    return function (dispatch) {
        const request = axios.post(`${LOGINLOOKUP_URL}`, credentials).then(function (response) {
            dispatch({
                type: LOGIN_SUCCESS,
                payload: true
            });
         })
         .catch(function (error) {
              dispatch({
                  type: LOGIN_FAIL,
                  payload: false
              });
         });
    }
}

This is about as simple as async actions get, and it's how the official Redux tutorial will teach you to do it - make sure to give those chapters a read, it's really helpful stuff!

redux-promise, on the other hand, lets you dispatch actions with a promise as the payload:

export function loginLookUp(credentials) {
    return {
        type: LOGIN,
        // Payload must be a promise!
        payload: axios.post(`${LOGINLOOKUP_URL}`, credentials)
    };
}

Rather than the action immediately being passed to the reducer, it will use .then() to wait for the promise in the payload to complete. Then, it will dispatch the action in one of two forms.

If the promise resolves, the action will be dispatched with the payload set to the resolved value, like so:

{
    type: LOGIN,
    payload: // The response from the server
}

If the promise fails, the action will be dispatched with the payload set to the rejected value and the error property set to true, like so:

{
    type: LOGIN,
    payload: // The error object,
    error: true
}

These are by no means the only ways of doing things - there's countless async action libraries, so if these both made you recoil in horror, there's bound to be something else that will suit you (I hear really good things from people smarter than me about redux-saga, but I can't comprehend it myself)!

Talking of sagas, this answer ended up being way longer than I intended. Hopefully it clears stuff up for you!

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks :) Do I place the thunk import on the component or the actions file?
@AndrewJuniorHoward: I'm not sure what you mean - the import for the redux-thunk library? If so, it's neither - redux-thunk is a middleware, so you import it when you're setting up your library. See github.com/gaearon/redux-thunk#installation. If I've misinterpreted you, let me know!
That's great thanks for your help. I think I need to do a bit more setup but having this example is really really useful. Thank you so much :)
@AndrewJuniorHoward: No problem! I think async stuff is a lot of people's first stumbling block when they're learning Redux.
For the redux-promise solution, do those last 2 blocks need to be in the reducers?
|

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.