Search code examples
javascriptreduxrxjsreactivexredux-observable

Integrating redux-observable into existing project - Uncaught TypeError: Cannot read property 'apply' of undefined


I'm trying to integrate redux-observable into an existing redux project by bypassing the existing interceptor for a simple action and passing it along to a new epic which currently should just map to a new action type. I'm getting the error:

Uncaught TypeError: Cannot read property 'apply' of undefined
    at app.js:217853
    at Array.map (<anonymous>)
    at merger (app.js:217852)
    at MapSubscriber.project (app.js:217918)
    at MapSubscriber../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (app.js:225604)
    at MapSubscriber../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (app.js:220361)
    at Subject../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next (app.js:220127)
    at Function.epicMiddleware.run (app.js:217952)
    at GenericProvider../src/bootstrap/bootstrapStore.js.exports.default [as $get] (app.js:299968)
    at Object.getService (app.js:46915)

when I load my project, which runs fine except for the action I'm trying to reimplement.

I suspect I'm not creating or exporting my epic properly, since the error seems to be happening when I try to call epicMiddleware.run(registry.rootEpic) in bootstrapStore.js:

const epicMiddleware = createEpicMiddleware();
[...]
export default function(registry) {
  const store = createStore([...]);
  epicMiddleware.run(registry.rootEpic);
  return store;
}

where registry.rootEpic is bootstrapped using BottleJS:

bottle.factory('rootEpic', require('./bootstrapRootEpic').default);
bottle.factory('store', require('./bootstrapStore').default);

bootstrapRootEpic.js looks like this:

import { combineEpics } from 'redux-observable';

import { createExercisesEpic } from 'src/actions/epics';

export default function(registry) {
  return combineEpics(createExercisesEpic);
}

createExercisesEpics is defined in src/actions/epics/index.js:

export default {
  createExercisesEpic: require('./createExercisesEpic').default
};

and createExercisesEpic.js looks like this:

import { mapTo } from 'rxjs/operators';
import { ofType } from 'redux-observable';

import {
  CREATE_EXERCISES,
  CREATE_EXERCISES_COMPLETED
} from 'src/actions/types';

export default function(action$) {
  return action$.pipe(
    ofType(CREATE_EXERCISES),
    mapTo({type: CREATE_EXERCISES_COMPLETED})
  );
}

Am I missing a step somewhere, or is maybe one of my variables improperly defined or accidentally undefined?


Solution

  • The problem was that I was trying to use this import style:

    import { createExercisesEpic } from 'src/actions/epics';
    

    which only works for functions exported as functions rather than as named properties of exported objects. I changed it to:

    import epics from 'src/actions/epics';
    
    export default function(registry) {
      return epics.createExercisesEpic;
    }