0

Here is the code of my Component UserHandler

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import * as actionCreators from '../../store/actions/actions';

class UserHandler extends Component {
  componentDidMount() {
    const { onInitUsers } = this.props;
    onInitUsers();
  }

  render() {
    // some code
    return (          
        {/* SOME JSX */}
    );
  }
}

const mapStateToProps = state => ({
  //    state to props mapping
});

const mapDispatchToProps = dispatch => ({
  onUserEdition: username => dispatch(actionCreators.editUser(username)),
  onUserSelection: username => dispatch(actionCreators.fetchSelectedUser(username)),
  onInitUsers: () => dispatch(actionCreators.initUsers()),
});

// PropTypes definition and defaultProps

export default connect(mapStateToProps, mapDispatchToProps)(UserHandler);

And in my actionCreators file, here's what I defined:

const initUsersStart = createAction(INIT_USERS_START);
const setUsers = createAction(SET_USERS, users => ({ users }));
const initUsersError = createAction(INIT_USERS_ERROR, error => ({ error }));


const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return axios.get('/users')
    .then(
      response => dispatch(setUsers(response.data)),
    )
    .catch(
      error => dispatch(initUsersError(error)),
    );
};

When I comment the onInitUsers(); call in the componentDidMount() function, I no more have the error. I want to understand why this is raising this error.

Finally, here's how my I create my store:

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

import App from './App';
import registerServiceWorker from './registerServiceWorker';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import reducer from './store/reducers/reducers';

const store = createStore(
  reducer, /* preloadedState, */
  applyMiddleware(thunk),
  /* eslint-disable no-undef */ /* eslint-disable no-underscore-dangle */
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  /* eslint-enable */
);

// const store = createStore(reducer);

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  /* eslint-disable no-undef */
  document.getElementById('root'),
  /* eslint-enable */
);
registerServiceWorker();

Please note that I have done some research before to find out what may be the root cause of such an error, and it seems that it could emanate from several causes. I checked the ones I found, but it didn't help.

4
  • Can you share the code of the createAction function?
    – Anas
    Commented Aug 27, 2018 at 20:13
  • The createAction function is from github.com/pauldijou/redux-act
    – devio
    Commented Aug 27, 2018 at 20:15
  • what happens if you do onInitUsers: actionCreators.initUsers ? Commented Aug 27, 2018 at 20:17
  • @TomaszRozmus: the error disappears, but how to trigger the action creator?
    – devio
    Commented Aug 27, 2018 at 20:37

3 Answers 3

2

Return your axios call thus whichever of the paths your logic follows, an object gets returned as needed by Redux.

const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return axios.get('/users')
    .then(
      response => dispatch(setUsers(response.data)),
    )
    .catch(
      error => dispatch(initUsersError(error)),
    );
};

After having tested your code I think the problem also lies in your store configuration. Middlewares should be applied as last argument of createStore function:

const store = createStore(
  reducer, /* preloadedState, */
  /* eslint-disable no-undef */ /* eslint-disable no-underscore-dangle */
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  /* eslint-enable */
  applyMiddleware(thunk),
);

I tested this with redux v.4.0.0 and react-redux v.5.0.7.

3
  • Done (thank you), but this doesn't solve the problem I encouter.
    – devio
    Commented Aug 27, 2018 at 20:43
  • Now you got rid of the error, apply the suggestion by @Laurenz Glück but in this way: const mapDispatchToProps = dispatch => ({ actions: bindActionCreators(actionCreators, dispatch), });. Then call it in componentDidMount() with: this.props.actions.initUsers();.
    – Dez
    Commented Aug 27, 2018 at 20:55
  • I did exactly what you've just suggested, and I still get Error: Actions must be plain objects. Use custom middleware for async actions.
    – devio
    Commented Aug 27, 2018 at 21:04
1

This was posted over in the React-Redux issues list, and I answered it there. I'll paste my solution here for completeness.

First, the root issue is that something that is not a plain action object is reaching the actual store. You could put a breakpoint in the dispatch function in the Redux source code to see what the actual value is (or edit the copy of Redux in your project's node_modules folder to add some logging).

Actually, I think I see the problem. The real issue is that you're passing two separate store enhancers to createStore. One is the middleware enhancer from applyMiddleware, the other is the Redux DevTools extension. You need to "compose" them both together into a combined enhancer. See the Configuring Your Store page in the Redux docs for a copy-pasteable example of how to do this properly.

Two other suggestions:

Instead of writing a mapDispatch function by hand, you can use the "object shorthand", and just pass an object full of action creators directly to connect. You already have an object full of action creators from the import * as actionCreators statement, so you can just do: export default connect(mapState, actionCreators)(UserHandler). (That said, the function names are not the same as the prop names you want, so you might need to make a new object instead like {onUserSelection : actionCreators.fetchSelectedUser} and pass that instead.)

Also, we've got a redux-starter-kit package we're working on that has a single function to set up your store for you, and automatically adds both redux-thunk and the DevTools Extension. You might want to try using that instead of setting up the store yourself.

1
  • Thank you @markerikson for your help. Appreciate it!
    – devio
    Commented Aug 28, 2018 at 0:11
0

The problem is, that your are dispatching an action with calling onInitUsers() because it's inside the dispatch() function. If you dispatch an action, you need to return an object with key type and optional a payload.

What you need is bindActionCreators function inside your mapDispatchToProps like this:

import { bindActionCreators } from "redux";

const mapDispatchToProps = dispatch => ({
  onUserEdition: username => dispatch(actionCreators.editUser(username)),
  onUserSelection: username => dispatch(actionCreators.fetchSelectedUser(username)),
  onInitUsers: bindActionCreators(actionCreators.initUsers, dispatch),
});

Now you have bind the dispatch function to your initUsers function an can use it like us want.


Edit: Try to change your onInitUser function to the following:

const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return dispatch({
            type: 'GET_USER',
            payload: axios.get('/users')
                .then(
                  response => dispatch(setUsers(response.data)),
                )
                .catch(
                  error => dispatch(initUsersError(error)),
                );
        });
};
4
  • I did this but it didn't solve the issue at all. I still get the same error.
    – devio
    Commented Aug 27, 2018 at 20:48
  • Made the changes exactly as you advised, but still facing the same issue
    – devio
    Commented Aug 27, 2018 at 21:31
  • Mmm okay, thats strange! I honestly never used something like that... Maybe you have a look at redux-logic: github.com/jeffbski/redux-logic It's pretty cool, I use it daily and it will make it really easy for you to do what you want. Let me know I you need some more informations... Commented Aug 27, 2018 at 21:42
  • Thanks @Laurenz but I'll have to stick for now to redux-thunk to deal with async calls in action creators, and hoopefully find a solution to this issue.
    – devio
    Commented Aug 27, 2018 at 21:49

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.