microsoft / redux-dynamic-modules

Modularize Redux by dynamically loading reducers and middlewares.

Home Page:https://redux-dynamic-modules.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use connected-react-router with redux-dynamic-module

jeevasusej opened this issue · comments

I have created typescript based website with react.
I am using react router dom.
I want to use connected react router.

I don't know where to add

router: connectRouter(history), and routerMiddleware(history)

I am using the following configuration while create store.

const store: IModuleStore = createStore(
{
extensions: [getSagaExtension()],
}
);

I have used the routerMiddleware(history) with the enhancer. But that shows error with the typings.

In my actual structure,
I have auth module,

export const AuthModule: ISagaModule<types.AuthState> = {
// Unique id of the module
id: 'auth',
// Maps the Store key to the reducer
reducerMap: {
authState: reducer,
},
// This module uses redux-saga middleware
// This property will be be used by the SagaExtension
// to run sagas for the moduleD
sagas: [authsaga],
};

I am sharing this module with the two container Home and Landing. This will have sub routes.

Where I am making mistakes? How should I correct it?

I commented with sample on #114 , so please refer to it.
But this demo by JavaScript, I'm sorry if you have TypeScript specific problems.

It might seem intimidating at first, but once you grasp the concept of modules, it becomes very easy.

Whenever you want to integrate any reducers or middleware, you use a module for that. You can create a module called routerModule and add it as an initial module when creating a store. Initial modules can be added as an additional argument to the store.

Here is the basic setup:

routerModule.ts:

import { createBrowserHistory, LocationState } from 'history';
import { connectRouter, routerMiddleware } from 'connected-react-router';
import { IModule } from 'redux-dynamic-modules';

export const history = createBrowserHistory();

export const routerModule: IModule<LocationState> = {
    id: 'startup',
    reducerMap: {
        router: connectRouter(history),
    } as any,
    middlewares: [routerMiddleware(history)],
};

And then use it in your root component as follows:

index.ts:

...
other imports
...
import { ConnectedRouter } from 'connected-react-router';
import { routerModule, history } from './modules/RouterModule';

const store: IModuleStore<{}> = createStore(
    {
        extensions: [getSagaExtension()]
    },
    routerModule,
);

// store.addModule(routerModule); // another way of adding a module

ReactDOM.render(
        <Provider store={store}>
            <ConnectedRouter history={history}>
                <App />
            </ConnectedRouter>
        </Provider>,
        document.getElementById('root'),
    );

Thank you for the response.
Do I need to add this routerModule to every module to be used in subsequent modules?
For example I am using AuthModule for the initial parent containers which is used in the parent routings (Private/Protected).
Typescript - example

export interface AuthState {
    userstate: UserState;
    locationstate: LocationState;
}
export const _authModule: ISagaModule<types.AuthState> = {
// Unique id of the module
id: 'auth',
// Maps the Store key to the reducer
reducerMap: {
authState: reducer,
},
// This module uses redux-saga middleware
// This property will be be used by the SagaExtension
// to run sagas for the moduleD
sagas: [authsaga],
};

export AuthModule = [routerModule,_authModule];
const mapStateToProps = (state: AuthState) => {
    return {
        isLoggedIn: state.authState.isLoggedIn,
        name: state.authState.name,
        pathname : state.locationstate.router.location.pathname,
    };
};

export const HomeContainer = () => (
    <DynamicModuleLoader modules={[AuthModule]}>
        <ConnectedOrder />
    </DynamicModuleLoader>
);

I commented with sample on #114 , so please refer to it.
But this demo by JavaScript, I'm sorry if you have TypeScript specific problems.

Good example. Thank you.

Do I need to add this routerModule to every module to be used in subsequent modules?

@jeevasusej, If you add it as an initial module, there is no need to add it again for subsequent modules.

Thank you @assainov
For strongly typed props, I have inherited the interface type from the root state.
Will it be a right approach?

export interface AuthState {
    authState: UserState;
}

export interface AuthMainState extends AuthState, RootState {}

const mapStateToProps = (state: AuthMainState ) => {
    return {
        isLoggedIn: state.authState.isLoggedIn,
        name: state.authState.name,
        pathname : state.router.location.pathname,
    };
};

@jeevasusej ,

For strongly typed props, I have inherited the interface type from the root state.
Will it be a right approach?

It's getting a bit off topic, but - yes, you can definitely extend it. The alternative approach would be to use a type alias:

type AuthMainState = AuthState | RootState;