2
votes

Creating my store with Thunk middleware

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
const store = createStore(
    reducer, 
    initialState,
    applyMiddleware(thunk)
);

And creating my action which calls a promise

export function getArticle(url) {
  return function (dispatch) {
    fetchArticle(url).then( 
      article => dispatch(setArticle(article)),
    );
  };
}

function fetchArticle(url) {

  return new Promise((resolve, reject) => {

    request
     .get(url)
     .end( (err, res) => {
       if (err || !res.ok) {
         reject('Oh no! error');
       } else {
         resolve(res.body);
       }
     });

  }) 
}

export function setArticle(article){
  return {
    type: constants.SET_ARTICLE,
    article
  }
}

In my article component I am calling dispatch on componentDidMount()

componentDidMount(){
  this.props.dispatch(
    getArticle('http://api.example.com/')
  );
}

But getting error: "Actions must be plain objects. Use custom middleware for async actions.".

What is wrong with this setup? I have tried calling compose(applyMiddleware(thunk)) but to no avail.

4
It may sound dumb but make sure you have redux-thunk installed, npm install redux-thunk. console.log thunk to make sure that exists. Your code looks fine, it just seems like thunk is not registering.Eric Kambestad

4 Answers

2
votes

Your code looks ok except that it's missing how to handle errors (promise rejection). Your api might be returning errors and you're not handling it which could result to that error message.

Try adding

export function getArticle(url) {
  return function (dispatch) {
    fetchArticle(url)
      .then(article => dispatch(setArticle(article)))
      .catch(err => dispatch({ type: 'SOME_ERROR', err }));
  };
}
0
votes

Change

return function (dispatch) {
    fetchArticle(url).then( 
      article => dispatch(setArticle(article)),
    );
  };

To

return function (dispatch) {
    return fetchArticle(url).then( 
      article => dispatch(setArticle(article)),
    );
  };
0
votes

Try the following:

export function getArticle(url) {
    return fetchArticle(url).then( 
      article => dispatch(setArticle(article)),
    );  
}
0
votes

In Redux every action must return an object.

You may use:

export const getArticle= url=> dispatch => {
 fetchArticle(url)
   .then(res =>
     dispatch({ type: SET_ARTICLE, payload: res.data })
   )
   .catch(err =>
     dispatch({
       type: GET_ERRORS,
       payload: err.response.data
     })
   );
};