React-Redux Action: 'Dispatch' is not a function

11,681

You have to do something like this:

export const getMetaOutsider = () => {
  return (dispatch) => {
    Axios.get("meta/outsiders")
    .then(res => {
      dispatch({ type: GET_OUTSIDER_META_INFORMATION, payload: res.data });
    })
    .catch(err =>
      dispatch({ type: POPULATE_ERRORS, payload: err.response.data })
    );
  }
};

Try this, It should work. Feedbacks are welcome. redux-thunk handles functions passed as the argument to dispatch instead of objects.

Share:
11,681

Related videos on Youtube

Chris Rutherford
Author by

Chris Rutherford

By day, wrangling applications and writing replacements for some at a wonderful Non-Profit, and by night, Trying to take over the world with fresh ideas.

Updated on June 04, 2022

Comments

  • Chris Rutherford
    Chris Rutherford almost 2 years

    Still getting used to Redux, first off. I have a component that should simply load data for display when the component loads. I have redux setup with the store:

    //store.js
    import { createStore, applyMiddleware, compose } from 'redux';
    
    import logger from 'redux-logger';
    import thunk from 'redux-thunk';
    import root from './reducers';
    
    const middleware = [thunk, logger];
    
    const initState = {};
    
    const store = createStore(
      root,
      initState,
      compose(
        applyMiddleware(...middleware),
        window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
      )
    );
    
    export default store;
    

    and all the reducers that I'll need in a full on combine reducers file:

    //{projectFolder}/reducers/index.js
    import { combineReducers } from 'redux';
    
    import authReducer from './authReducer';
    import errorsReducer from './errorReducer';
    import suggestionReducer from './suggestionReducer';
    import insiderReducer from './insiderReducer';
    import connectionReducer from './connectionReducer';
    import outsiderReducer from './outsiderReducer';
    import contactReducer from './contactReducer';
    import metaReducer from './metaReducer';
    
    export default combineReducers({
      auth: authReducer,
      errors: errorsReducer,
      suggestions: suggestionReducer,
      insider: insiderReducer,
      connection: connectionReducer,
      outsider: outsiderReducer,
      contact: contactReducer,
      meta: metaReducer
    });
    

    The one that I'm interested in is the metaReducer which is the called by an action, or so it should be.

    //metaReducer.js
    import {GET_INSIDER_META_INFORMATION, GET_OUTSIDER_META_INFORMATION } from '../actions/types';
    
    const initState = {
      insider: {},
      outsider: {}
    };
    
    export default (state = initState, { type, payload }) => {
      switch (type) {
        case GET_INSIDER_META_INFORMATION:
            return{
                ...state,
                insider: payload
            }
        case GET_OUTSIDER_META_INFORMATION:
            return {
                ...state,
                outsider: payload
            }
        default:
          return state;
      }
    };
    

    The meta reducer is just to house the information coming from the back-end and is each case of the reducer is called from the actions/meta.js file which looks like this:

    //{projectfolder}/actions/meta.js
    import {
      GET_INSIDER_META_INFORMATION,
      GET_OUTSIDER_META_INFORMATION,
      POPULATE_ERRORS
    } from "./types";
    import Axios from "axios";
    
    export const getMetaInsider = (dispatch) => {
      return Axios.get("meta/insiders")
        .then(res =>
          dispatch({ type: GET_INSIDER_META_INFORMATION, payload: res.data })
        )
        .catch(err =>
          dispatch({ type: POPULATE_ERRORS, payload: err.response.data })
        );
    };
    
    export const getMetaOutsider = (dispatch) => {
      return Axios.get("meta/outsiders")
        .then(res => {
          dispatch({ type: GET_OUTSIDER_META_INFORMATION, payload: res.data });
        })
        .catch(err =>
          dispatch({ type: POPULATE_ERRORS, payload: err.response.data })
        );
    };
    

    and My component that calls all of this is setup as below:

    //{projectfolder}/components/home.js
    import React, {Component} from 'react';
    import {Card, CardTitle, CardSubtitle, CardBody} from 'reactstrap';
    import { connect } from 'react-redux';
    import PropTypes from 'prop-types';
    import {getMetaInsider, getMetaOutsider} from '../actions/meta';
    
    class Home extends Component{
      constructor(props){
        super(props);
        this.state = {
          insider:{},
          outsider: {}
        }
      }
      componentDidMount() {
        console.log(this.props);
        this.props.getMetaInsider();
        this.props.getMetaOutsider();
      }
      render(){
        let {insiders, outsiders} = this.state;
        return(
          <React.Fragment>
            {*/ omitted as it's not really an issue right now, data is more important than layout /*}
          </React.Fragment>
        )
      }
    }
    
    const mapState = state => {
     console.log(state);
    
     return {
      insider: state.meta.insider,
      outsider: state.meta.outsider
     }
    };
    
    Home.propTypes = {
      getMetaInsider: PropTypes.func.isRequired,
      getMetaOutsider: PropTypes.func.isRequired,
      insider: PropTypes.object.isRequired,
      outsider: PropTypes.object.isRequired
    };
    
    export default connect(mapState, {getMetaInsider, getMetaOutsider})(Home);
    

    So when the component loads, I get a horribly weird issue where it looks like jquery is being called, and it's imported in my App.js file for bootstrap. However, the main error is this:

    "TypeError: dispatch is not a function at http://localhost:3000/static/js/bundle.js:73524:22"

    Which maps up to the .catch block of the getMetaInsider function.

    • simbathesailor
      simbathesailor over 5 years
      You need to wrap your async action creators return functions inside another function.
  • Chris Rutherford
    Chris Rutherford over 5 years
    I had a previous project from a long tutorial that did that and i didn't understand why I had to do that. Now I do! Thanks @simbathesailor
  • simbathesailor
    simbathesailor over 5 years
    so what happens, is you pass the actions bound with dispatch function to your dumbcomponents(using bindActioncreators or manually). Now, whenever you call a function bound with dispatch you, generally call it and if the action is tend to do something asynchronous, you need to return a function out of it , not a value. That's where redux -thunk comes in the picture and handles the dispatch flow. redux-thunk will take the returned function and call it with passing store.dispatch as the argument. thats how it is available in your returned function. Thanks. read more at redux website. Thanks