microsoft / redux-dynamic-modules

Modularize Redux by dynamically loading reducers and middlewares.
https://redux-dynamic-modules.js.org
MIT License
1.07k stars 116 forks source link

redux-dynamic-modules-observable: Support for Injecting Dependencies #145

Open LFFATE opened 4 years ago

LFFATE commented 4 years ago

Almost done with migration to redux-dynamic-modules, but I can't make my epics working. I use Dependencies Injection because of unit testing:

https://redux-observable.js.org/docs/recipes/InjectingDependenciesIntoEpics.html

import { createEpicMiddleware, combineEpics } from 'redux-observable';
import { ajax } from 'rxjs/ajax';
import rootEpic from './somewhere';

const epicMiddleware = createEpicMiddleware({
  dependencies: { getJSON: ajax.getJSON }
});

epicMiddleware.run(rootEpic);

and, for example, I try to create initial store:

export const store = createStore({
  initialState: persistedState,
  enhancers: [applyMiddleware(epicMiddleware)],
  extensions: [getObservableExtension()],
}, commonModule())

And I see that epics are called, but at the moment it calls for dependency - it crushes because of undefined

Any suggestions please?

And another question:

epicMiddleware.run(rootEpic) - rootEpic is any type, but with redux-dynamic-modules we should use Epic[] here:

export function commonModule(): IEpicModule<ModuleState> {
  return {
      id: 'module',
      reducerMap: moduleReducer,
      epics: moduleEpics,
  }
}

Where any - type from redux-observable, and I see that Epic type from redux-dynamic-modules-observable allows dependencies:

interface Epic<Input extends Action<any> = any, Output extends Input = Input, State = any, Dependencies = any>

Should I manually call epicMiddleware.run and what argument with?

LFFATE commented 4 years ago

Looks like I should move middleware from store to module:

export function commonModule(): IEpicModule<ModuleState> {
  return {
      id: 'module',
      reducerMap: moduleReducer,
      epics: moduleEpics,
      middlewares: [epicMiddleware]
  }
}

But problem with dependencies still actual and appears a new problem:

redux-observable | WARNING: this middleware is already associated with a store. createEpicMiddleware should be called for every store.

But there is just one store at the moment

LFFATE commented 4 years ago

So, I think I found the problem. And I think I can create a PR, just check my explorations:

// create deps object to be accessible in epics
const options= { dependencies: { ... }}

export const store = createStore({
  initialState: persistedState,
  // pass it to extension creator
  extensions: [getObservableExtension(options)],
}, commonModule())

inside https://github.com/microsoft/redux-dynamic-modules/blob/master/packages/redux-dynamic-modules-observable/src/index.ts:

export function getObservableExtension(options?: Options): IExtension {
    const epicMiddleware = createEpicMiddleware(options);
...
}

where Options is:

interface Options<D = any> {
  dependencies?: D;
}

this type directly from redux-observable, but the library doesn't export it