3

I am getting Unhandled Rejection (Error): Actions must be plain objects. Use custom middleware for async actions. I want to call the "news api" endpoint to fetch the news and render them on the page.

Here is my code for action:

import * as types from './newsApiTypes';

const API_KEY = "6c78608600354f199f3f13ddb0d1e71a";

export const getNewsAPI = () => {
  return (dispatch, getState) => {
    dispatch({
      type: 'API_REQUEST',
      options: {
        method: 'GET',
        endpoint: `https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=${API_KEY}`,
        actionTypes: {
          success: types.GET_NEWS_API_SUCCESS,
          error: types.GET_NEWS_API_ERROR
        }
      }
    });
  }
}

Here is my code for reducer:

import * as types from '../actions/newsApiTypes';

const initialState = {
  newNews: []
};

const getNewsAPIReducer = (state = initialState, action) => {
  switch(action.type) {
    case types.GET_NEWS_API_SUCCESS:
      return { ...state, newNews: action.data };

    case types.GET_NEWS_API_ERROR:
      return { ...state, error: action.data };

    default: {
      return state;
    };
  };
};

export default getNewsAPIReducer;

Here is my code for action types:

export const GET_NEWS_API = 'GET_NEWS_API';
export const GET_NEWS_API_SUCCESS = 'GET_NEWS_API_SUCCESS';
export const GET_NEWS_API_ERROR = 'GET_NEWS_API_ERROR';

Here is my Index.js with creating store with applyMiddleware:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';

import App from './components/app';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <App />
  </Provider>,
  document.querySelector('.container')
);

Here is my code for root reducers:

import { combineReducers } from 'redux';
import NewsReducer from './reducer_news';
import KickstarterReducer from './reducer_kickstarter';
import NewsApiReducer from './newsApiReducer.js';

const rootReducer = combineReducers({
  news: NewsReducer,
  kickstarters: KickstarterReducer,
  newNews: NewsApiReducer
});

export default rootReducer;

Could anyone please help me why I am getting that unhandled error?

Thank you.

tanmay
  • 7,761
  • 2
  • 19
  • 38
Eunicorn
  • 601
  • 6
  • 16
  • 29
  • Can you post your `redux config` file / module ? – Pritish Vaidya Apr 05 '18 at 04:18
  • are you using any middleware? if no then check this ans [why do we need middleware for async flow](https://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux) – Mayank Shukla Apr 05 '18 at 04:22
  • @PritishVaidya I updated my post. Please take a look. – Eunicorn Apr 05 '18 at 04:37
  • @MayankShukla Yes I am using it. Please take a look at the updated post. – Eunicorn Apr 05 '18 at 04:37
  • your action looks like it is using `redux-thunk` but your config says otherwise.. – tanmay Apr 05 '18 at 04:48
  • @Eunicorn, This could help you https://stackoverflow.com/questions/47541032/handling-async-request-with-react-redux-and-axios/47588228#47588228. you seem to be mixing the code syntax for redux-thunk and redux-promise – Shubham Khatri Apr 05 '18 at 05:47
  • Your action looks like it is supposed to work with an API middleware instead of redux-promise. Where you trying something like [redux-api-middleware](https://github.com/agraboso/redux-api-middleware) ? – miles_christian Apr 05 '18 at 08:52

2 Answers2

1

A great article that can help is redux 4 ways.

Regarding the code.

With redux-promise (which I see that you are using now) you should write:

export const getNewsAPI = () => {
  return {
      type: 'API_REQUEST',
      options: {
        method: 'GET',
        endpoint: `https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=${API_KEY}`,
        actionTypes: {
          success: types.GET_NEWS_API_SUCCESS,
          error: types.GET_NEWS_API_ERROR
        }
      }

Or, with redux-thunk:

Instead of:

export const getNewsAPI = () => {
  return (dispatch, getState) => {
    dispatch({
      type: 'API_REQUEST',
      options: {
        method: 'GET',
        endpoint: `https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=${API_KEY}`,
        actionTypes: {
          success: types.GET_NEWS_API_SUCCESS,
          error: types.GET_NEWS_API_ERROR
        }
      }
    });
  }
}

Use:

function actionCreator() {
  return {
          type: 'API_REQUEST',
          options: {
            method: 'GET',
            endpoint: `https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=${API_KEY}`,
            actionTypes: {
              success: types.GET_NEWS_API_SUCCESS,
              error: types.GET_NEWS_API_ERROR
            }
          }  
      }
}

and:

export const getNewsAPI = () => {
  return function (dispatch) {
    dispatch(actionCreator())
    }
Yossi
  • 5,577
  • 7
  • 41
  • 76
  • Thank you for your answer. However, even with your answer, I still get the same error. – Eunicorn Apr 05 '18 at 04:40
  • And you use redux-thunk? I see redux-promise in your code . I added code for redux-promise to my answer. – Yossi Apr 05 '18 at 04:58
0

Your action looks like it is using redux-thunk but your config says otherwise.

I'm new to react as well so I'm not 100% sure, but try this configuration (after installing redux-thunk of course):

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import ReduxPromise from 'redux-promise';

import App from './components/app';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(thunk, ReduxPromise)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <App />
  </Provider>,
  document.querySelector('.container')
);
tanmay
  • 7,761
  • 2
  • 19
  • 38