"Cannot read property 'type' of undefined" in redux store for action defined in external package

12,955

The problem might be in declaration of hideSnackBar function

export const hideSnackBar = () => {
    type: SNACKBAR_HIDE
};

Here the function is trying to return an Object Literal from Arrow Function. This will always return undefined. As the parser doesn't interpret the two braces as an object literal, but as a block statement. Thus the error, Cannot read property 'type' of undefined as store is expecting an action with property type.

Replace code like this and see if it works.

export const hideSnackBar = () => ({
    type: SNACKBAR_HIDE
});

The parentheses forces it to parse as Object Literal. Hope this helps

Share:
12,955

Related videos on Youtube

Tom Troughton
Author by

Tom Troughton

Updated on June 04, 2022

Comments

  • Tom Troughton
    Tom Troughton almost 2 years

    As part of my ongoing project to learn React (I'm natively an ASP.NET guy) I've hit this issue. I have a suite of React apps in which I want to use some common UI elements, so I've attempted to break these out into a separate npm package. For the shared components themselves this has worked fine.

    However, some of these components depend on redux actions to operate, so I've tried to bundle these actions and a reducer function into the external package. Here's a simplified version of my actions\index.js:

    export const SNACKBAR_MESSAGE = "SNACKBAR_MESSAGE";
    export const SNACKBAR_HIDE = "SNACKBAR_HIDE";
    
    export function showSnackBarMessage(message) {
        console.log('hit 1');
        return (dispatch, getState) => {
            console.log('hit 2');
            dispatch(hideSnackBar());
            dispatch({
                type: SNACKBAR_MESSAGE,
                message: message
            });
        }
    }
    
    export const hideSnackBar = () => {
        type: SNACKBAR_HIDE
    };
    

    And this is reducer\index.js:

    import { 
        SNACKBAR_MESSAGE,
        SNACKBAR_HIDE
    } from "../actions";
    
    const initialState = {
        snackBarMessage: null,
        snackBarVisible: false
    };
    
    export default function UiReducer(state = initialState, action) {
        switch(action.type) {
            case SNACKBAR_MESSAGE:
                return Object.assign({}, state, { 
                    snackBarMessage: action.message,
                    snackBarVisible: true
                });
            case SNACKBAR_HIDE:
                return Object.assign({}, state, { 
                    snackBarMessages: '',
                    snackBarVisible: false
                });
            default:
                return state;
        }
    }
    

    This is the same code that worked fine when part of the original project. These are exported by my package's entry point file like this:

    // Reducer
    export { default as uiReducer } from './reducer';
    
    // Actions
    export { showSnackBarMessage as uiShowPrompt } from './actions';
    export { hideSnackBar as uiHidePrompt } from './actions';
    

    Then in my consuming project, my default reducer looks like this:

    import { routerReducer } from 'react-router-redux';
    import { combineReducers } from 'redux';
    import { uiReducer } from 'my-custom-ui-package';
    // Import local reducers
    
    const reducer = combineReducers(
      {
        // Some local reducers
        ui: uiReducer
      }
    );
    
    export default reducer;
    

    The problem is when I try to dispatch one of these actions imported from my external package. I include the action, e.g. import { uiShowPrompt } from "my-custom-ui-package"; and dispatch it like dispatch(uiShowPrompt("Show me snackbar")); then I see the two console messages (hit 1 and hit 2) displayed, but then the following error:

    Uncaught TypeError: Cannot read property 'type' of undefined

    at store.js:12
    at dispatch (applyMiddleware.js:35)
    at my-custom-ui-package.js:1
    at index.js:8
    at middleware.js:22
    at store.js:15
    at dispatch (applyMiddleware.js:35)
    at auth.js:28
    at index.js:8
    at middleware.js:22
    

    The store itself looks like this:

    import { createStore, combineReducers, applyMiddleware, compose } from "redux";
    import thunk from 'redux-thunk';
    import { browserHistory } from "react-router";
    import {
      syncHistoryWithStore,
      routerReducer,
      routerMiddleware
    } from "react-router-redux";
    import reducer from "./reducer";
    
    const loggerMiddleware = store => next => action => {
        console.log("Action type:", action.type);
        console.log("Action payload:", action.payload);
        console.log("State before:", store.getState());
        next(action);
        console.log("State after:", store.getState());
    };
    
    const initialState = {};
    
    const createStoreWithMiddleware = compose(
      applyMiddleware(
        loggerMiddleware, 
        routerMiddleware(browserHistory), 
        thunk)
    )(createStore);
    
    const store = createStoreWithMiddleware(reducer, initialState);
    
    export default store;
    

    I'm afraid I don't understand this error. I don't see what I'm doing differently other than essentially moving identical code from my local project to an npm package. Since neither the actions nor reducer actually depend on redux, my npm package doesn't itself have a dependency on react-redux. Is that a problem? If there's anything else I could share to help you help me just let me know. Like I say, I'm still fairly new to all this so clearly there's something I'm not getting right!

  • Tom Troughton
    Tom Troughton over 5 years
    Absolutely right. Thank you for the detailed explanation too. Of course now I remember removing those parentheses when I created the package, thinking I was tidying up! Next time I'll be more careful.
  • mfcss
    mfcss over 3 years
    I've run into a somewhat similar issue described here: stackoverflow.com/questions/63622988/… - if possible, your inputs would be helpful