bier hier
bier hier

Reputation: 22540

Why do I get a 'Actions must be plain objects' error?

I am just learning react-redux and trying to fire a thunk, this is the thunk:

const getRepos = dispatch => {
  try {
    const url = `https://api.github.com/users/reduxjs/repos?sort=updated`;
    fetch(url)
      .then(response => response.json())
      .then(json => {
        console.log("thunk: getrepos data=", json);
      });
  } catch (error) {
    console.error(error);
  }
};

I hooked up my component to the store:

const bla = dispatch =>
  bindActionCreators(
    {
      geklikt,
      getRepos
    },
    dispatch
  );

const Container = connect(
  null,
  bla
)(Dumb);

When I trigger the getRepos thunk I get:

Actions must be plain objects. Use custom middleware for async actions.

What could be the issue? I included the middleware? link to code sandbox

Upvotes: 1

Views: 62

Answers (2)

Matt Carlotta
Matt Carlotta

Reputation: 19762

Please refactor your application structure, it's all in one file and extremely hard to read.

Things to consider:

In the meantime, here's a working version: https://codesandbox.io/s/oxwm5m1po5

actions/index.js

import { GEKLIKT } from "../types";

export const getRepos = () => dispatch =>
  fetch(`https://api.github.com/users/reduxjs/repos?sort=updated`)
    .then(res => res.json())
    .then(data => dispatch({ type: GEKLIKT, payload: data }))
    .catch(err => console.error(err.toString()));

/*
  export const getRepos = () => async dispatch => {
    try {
      const res = await fetch(`https://api.github.com/users/reduxjs/repos?sort=updated`)
      const data = await res.json();
      dispatch({ type: GEKLIKT, payload: data }))
    } catch (err) { console.error(err.toString())}
  }
*/

components/App.js

import React from "react";
import Dumb from "../containers/Dumb";

export default () => (
  <div className="App">
    <Dumb />
  </div>
);

containers/Dumb.js

import React from "react";
import { connect } from "react-redux";
import { getRepos } from "../actions";

let Dumb = ({ data, getRepos }) => (
  <div>
    hi there from Dumb
    <button onClick={getRepos}>hier</button>
    <pre>
      <code>{JSON.stringify(data, null, 4)}</code>
    </pre>
  </div>
);

export default connect(
  state => ({ data: state.data }),
  { getRepos }
)(Dumb);

reducers/index.js

import { combineReducers } from "redux";
import { GEKLIKT } from "../types";

const klikReducer = (state = {}, { payload, type }) => {
  switch (type) {
    case GEKLIKT:
      return { ...state, data: payload };
    default:
      return state;
  }
};

export default combineReducers({
  data: klikReducer
});

root/index.js

import React from "react";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import thunk from "redux-thunk";
import rootReducer from "../reducers";
import App from "../components/App";

const store = createStore(rootReducer, applyMiddleware(thunk));

export default () => (
  <Provider store={store}>
    <App />
  </Provider>
);

types/index.js

export const GEKLIKT = "GEKILKT";

index.js

import React from "react";
import { render } from "react-dom";
import App from "./root";
import "./index.css";

render(<App />, document.getElementById("root"));

Upvotes: 1

Hemadri Dasari
Hemadri Dasari

Reputation: 33994

You returned the promise in action. A promise is not a plain object and so the returned action would not be a plain object and hence the error.

Since you're using the thunk middleware your actions can be functions and here's how you'd do it.

  const GET_REPOS_REQUEST = "GET_REPOS_REQUEST";
  const GET_REPOS_SUCCESS = "GET_REPOS_SUCCESS";
  const GET_REPOS_ERROR = "GET_REPOS_ERROR";
  export function getRepos() {
      return function action(dispatch) {
        dispatch({type: GET_REPOS})
       const url = `https://api.github.com/users/reduxjs/repos?sort=updated`;
       const request = fetch(url);
       return request.then(response => response.json())
        .then(json => {
            console.log("thunk: getrepos data=", json);
            dispatch({type: GET_REPOS_SUCCESS, json});
        })
       .then(err => {
            dispatch({type: GET_REPOS_ERROR, err});
            console.log(“error”, err);
       });
  };
  }

Arrow function way:

export getRepos = () =>{
  return action = dispatch => {
    dispatch({type: GET_REPOS})
   const url = `https://api.github.com/users/reduxjs/repos?sort=updated`;
   const request = fetch(url);
   return request.then(response => response.json())
    .then(json => {
        console.log("thunk: getrepos data=", json);
        dispatch({type: GET_REPOS_SUCCESS, json});
    })
   .then(err => {
        console.log(“error”, err);
        dispatch({type: GET_REPOS_ERROR, err});
   });
};}

Upvotes: 1

Related Questions