This commit is contained in:
crusader 2017-07-25 15:06:59 +09:00
parent 81049e375f
commit bf344fc561
7 changed files with 131 additions and 129 deletions

View File

@ -1,3 +1,6 @@
import { ReducersMapObject } from 'redux';
import signInReducer from '@overflow/member/redux/reducer/signIn';
// Container Configuration // Container Configuration
export interface ContainerConfig { export interface ContainerConfig {
placeholderID: string; placeholderID: string;
@ -14,16 +17,35 @@ const rpcConfig: RPCConfig = {
url: 'ws://127.0.0.1:18081/rpc', url: 'ws://127.0.0.1:18081/rpc',
}; };
// Redux Configuration
export interface ReduxConfig {
state: ReduxState;
reducerMaps: ReducersMapObject[];
}
export interface ReduxState {
}
const reduxState: ReduxState = {};
const reduxConfig: ReduxConfig = {
state: reduxState,
reducerMaps: [
signInReducer,
],
};
// Configuration // Configuration
export interface Config { export interface Config {
container: ContainerConfig; container: ContainerConfig;
rpc: RPCConfig; rpc: RPCConfig;
redux: ReduxConfig;
} }
const config: Config = { const config: Config = {
container: containerConfig, container: containerConfig,
rpc: rpcConfig, rpc: rpcConfig,
redux: reduxConfig,
}; };
export default config; export default config;

View File

@ -1,10 +1,36 @@
import * as React from 'react'; import * as React from 'react';
import * as ReactDOM from 'react-dom'; import * as ReactDOM from 'react-dom';
import { Provider, Store } from 'react-redux'; import {
import { ConnectedRouter } from 'react-router-redux'; applyMiddleware,
import createSagaMiddleware, { SagaMiddleware } from 'redux-saga'; compose,
import { History } from 'history'; createStore,
import { AppContainer } from 'react-hot-loader'; GenericStoreEnhancer,
Middleware,
Store,
} from 'redux';
import {
Provider,
} from 'react-redux';
import {
ConnectedRouter,
routerMiddleware,
} from 'react-router-redux';
import createSagaMiddleware, {
SagaMiddleware,
} from 'redux-saga';
import {
createHashHistory,
History,
} from 'history';
import {
AppContainer,
} from 'react-hot-loader';
import * as injectTapEventPlugin from 'react-tap-event-plugin'; import * as injectTapEventPlugin from 'react-tap-event-plugin';
@ -12,12 +38,9 @@ import Platform from '@overflow/commons/platform';
import AppContext from '@overflow/commons/context'; import AppContext from '@overflow/commons/context';
import * as AppContextLifecycleActions from '@overflow/commons/context/redux/action/lifecycle'; import * as AppContextLifecycleActions from '@overflow/commons/context/redux/action/lifecycle';
import WebSocketRPC from '@overflow/commons/websocket/WebSocketRPC'; import WebSocketRPC from '@overflow/commons/websocket/WebSocketRPC';
import ReducerManager from '@overflow/commons/redux/ReducerManager'; import ReducerContext from '@overflow/commons/redux/ReducerContext';
import appConfig, { Config, ReduxState } from './config';
import { store, sagaMiddleware, history } from './redux/store';
import appConfig, { Config } from './config';
import sagas from './redux/saga'; import sagas from './redux/saga';
// import routes from './router'; // import routes from './router';
@ -26,9 +49,13 @@ import App from './views/App';
injectTapEventPlugin(); injectTapEventPlugin();
const isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false; // const isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false;
// const useReduxDevTools = window.devToolsExtension && !isProduction ? true : false;
class Application { class Application {
private static isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false;
private static useReduxDevTools:boolean = window.devToolsExtension && !Application.isProduction ? true : false;
private config: Config; private config: Config;
private container: HTMLElement; private container: HTMLElement;
private context: AppContext; private context: AppContext;
@ -36,14 +63,11 @@ class Application {
private store: Store<any>; private store: Store<any>;
private sagaMiddleware: SagaMiddleware<any>; private sagaMiddleware: SagaMiddleware<any>;
private history: History; private history: History;
private reducerManager: ReducerManager;
public constructor() { public constructor() {
this.config = appConfig; this.config = appConfig;
this.sagaMiddleware = sagaMiddleware; this.history = createHashHistory();
this.store = store;
this.history = history;
this.reducerManager = new ReducerManager();
} }
public static Run(): void { public static Run(): void {
@ -58,7 +82,8 @@ class Application {
this.context = await this.initContext(); this.context = await this.initContext();
// this.rpcClient = await this.initRpcClient(); // this.rpcClient = await this.initRpcClient();
await this.initSagaEffect();
await this.initRedux();
this.store.dispatch(AppContextLifecycleActions.initialized()); this.store.dispatch(AppContextLifecycleActions.initialized());
@ -97,21 +122,30 @@ class Application {
const init = new Promise<void>(resolve => { const init = new Promise<void>(resolve => {
// state tree // state tree
// reducer // reducer
for (let reducerMap of this.config.redux.reducerMaps) {
ReducerContext.putReducers(reducerMap);
}
// middleware // middleware
let middlewares: Middleware[] = new Array();
this.sagaMiddleware = createSagaMiddleware();
middlewares.push(this.sagaMiddleware);
let routerReduxMiddleware = routerMiddleware(this.history);
middlewares.push(routerReduxMiddleware);
// store
let middleware: GenericStoreEnhancer = applyMiddleware(...middlewares);
this.store = createStore(
ReducerContext.reducer,
this.config.redux.state,
Application.useReduxDevTools ? compose(middleware, window.devToolsExtension()) : middleware,
);
// saga // saga
});
return init;
}
private initSagaEffect(): Promise<void> {
const rpcClient = new Promise<void>(resolve => {
this.sagaMiddleware.run(sagas); this.sagaMiddleware.run(sagas);
resolve(); resolve();
}); });
return rpcClient; return init;
} }
private displayLoading(): void { private displayLoading(): void {
@ -148,7 +182,7 @@ class Application {
private displayApp(): void { private displayApp(): void {
isProduction ? this.displayProductionApp() : this.displayDebugApp(); Application.isProduction ? this.displayProductionApp() : this.displayDebugApp();
} }
private displayProductionApp(): void { private displayProductionApp(): void {
ReactDOM.render( ReactDOM.render(

View File

@ -1,17 +0,0 @@
import { Action, combineReducers } from 'redux';
import State from '../state';
import { reducer as signinReducer} from '@overflow/member/redux/reducer/signIn';
import { reducer as signoutReducer} from '@overflow/member/redux/reducer/signOut';
import { reducer as signupReducer} from '@overflow/member/redux/reducer/signUp';
import { ConnectedRouter } from 'react-router-redux';
const reducer = combineReducers<State>({
signinReducer,
signoutReducer,
signupReducer,
});
export default reducer;

View File

@ -1,5 +0,0 @@
interface State {
}
export default State;

View File

@ -1,47 +0,0 @@
import {
applyMiddleware,
compose,
createStore,
Store,
} from 'redux';
import { routerMiddleware } from 'react-router-redux';
import createSagaMiddleware, {
SagaMiddleware,
} from 'redux-saga';
import {
createHashHistory,
History,
} from 'history';
import {
EnhancerOptions,
composeWithDevTools,
} from 'redux-devtools-extension/logOnlyInProduction';
import reducer from './reducer';
import State from './state';
const useReduxDevTools = window.devToolsExtension && process.env.NODE_ENV !== 'production' ? true : false;
const history = createHashHistory();
const sagaMiddleware: SagaMiddleware<any> = createSagaMiddleware();
const middlewares = [sagaMiddleware, routerMiddleware(history)];
const store: Store<State> = createStore<State>(
reducer,
useReduxDevTools ?
compose(
applyMiddleware(...middlewares),
window.devToolsExtension(),
)
:
applyMiddleware(...middlewares),
);
export {
history,
sagaMiddleware,
store,
};

View File

@ -2,55 +2,59 @@ import Action from './Action';
import * as Redux from 'redux'; import * as Redux from 'redux';
interface ReducerItem<State> { interface ReducerItem<State> {
initialState: State;
reducer: Redux.Reducer<State>; reducer: Redux.Reducer<State>;
} }
class ReducerManager { class ReducerContext {
private static instance: ReducerContext = new ReducerContext();
private reducerMap: Map<string, ReducerItem<any>[]>; private reducerMap: Map<string, ReducerItem<any>[]>;
public constructor() { private constructor() {
this.reducerMap = new Map(); this.reducerMap = new Map();
} }
public putReducer<State>(type: string, initialState: State, reducer: Redux.Reducer<State>): void { public static getInstance(): ReducerContext {
return ReducerContext.instance;
}
public static putReducers(handlers: Redux.ReducersMapObject): void {
for(let type in handlers) {
if (handlers.hasOwnProperty(type)) {
ReducerContext.getInstance().putReducer(type, handlers[type]);
}
}
}
public static reducer<State, A extends Action>(state: State, action: A): State {
const actionType = action.type;
if (ReducerContext.getInstance().reducerMap.has(actionType)) {
let reducerItems = ReducerContext.getInstance().reducerMap.get(actionType);
for (let reducerItem of reducerItems) {
let reducer = reducerItem.reducer;
state = reducer(state, action);
}
} else {
console.log(`Reducer for [${actionType}] is not exist in the context.`);
}
return state;
}
private putReducer<State>(type: string, reducer: Redux.Reducer<State>): void {
let reducerItems: ReducerItem<any>[]; let reducerItems: ReducerItem<any>[];
if (!this.reducerMap.has(type)) { if (!this.reducerMap.has(type)) {
reducerItems = new Array(); reducerItems = new Array();
this.reducerMap.set(type, reducerItems); this.reducerMap.set(type, reducerItems);
} else { } else {
reducerItems = this.reducerMap.get(type); reducerItems = this.reducerMap.get(type);
console.log(`Count of reducer[${type}] is ${reducerItems.length + 1}`);
} }
let reducerItem: ReducerItem<State> = { let reducerItem: ReducerItem<State> = {
initialState: initialState,
reducer: reducer, reducer: reducer,
}; };
reducerItems.push(reducerItem); reducerItems.push(reducerItem);
} }
public putReducers<State>(initialState: State, handlers: Redux.ReducersMapObject): void {
for(let type in handlers) {
if (handlers.hasOwnProperty(type)) {
this.putReducer(type, initialState, handlers[type]);
}
}
}
public reducer<State, A extends Action>(state: State, action: A): State {
const actionType = action.type;
if (this.reducerMap.has(actionType)) {
let reducerItems = this.reducerMap.get(actionType);
for (let reducerItem of reducerItems) {
let initialState = reducerItem.initialState;
let reducer = reducerItem.reducer;
state = reducer(state, action);
}
} else {
console.log(`Reducer for [${actionType}] is not loaded.`);
}
return state;
}
} }
export default ReducerManager; export default ReducerContext;

View File

@ -1,21 +1,32 @@
import Action from '@overflow/commons/redux/Action'; import Action from '@overflow/commons/redux/Action';
import { ReducersMapObject } from 'redux';
import createReducer from '@overflow/commons/redux/createReducer'; import createReducer from '@overflow/commons/redux/createReducer';
import Member from '@overflow/member/api/model/Member'; import Member from '@overflow/member/api/model/Member';
import * as SigninActionTypes from '../action/signIn'; import * as SigninActionTypes from '../action/signIn';
import SigninState, { defaultState as signinDefaultState } from '../state/SignIn'; import SigninState, { defaultState as signinDefaultState } from '../state/SignIn';
export type reducer = (state: SigninState, action: Action<Member | Error>) => SigninState; // export type reducer = (state: SigninState, action: Action<Member | Error>) => SigninState;
export const reducer: reducer = createReducer(signinDefaultState, { // export const reducer: reducer = createReducer(signinDefaultState, {
[SigninActionTypes.REQUEST_SUCCESS]: (state: SigninState, action: Action<Member>): SigninState => { // [SigninActionTypes.REQUEST_SUCCESS]: (state: SigninState = signinDefaultState, action: Action<Member>): SigninState => {
// return state;
// },
// [SigninActionTypes.REQUEST_FAILURE]: (state: SigninState = signinDefaultState, action: Action<Error>): SigninState => {
// return state;
// },
// });
const reducer: ReducersMapObject = {
[SigninActionTypes.REQUEST_SUCCESS]: (state: SigninState = signinDefaultState, action: Action<Member>): SigninState => {
return state; return state;
}, },
[SigninActionTypes.REQUEST_FAILURE]: (state: SigninState, action: Action<Error>): SigninState => { [SigninActionTypes.REQUEST_FAILURE]: (state: SigninState = signinDefaultState, action: Action<Error>): SigninState => {
return state; return state;
}, },
}); };
export default reducer;
// export const reducer: reducer = (state: SigninState = signinDefaultState, action: Action<Member | Error>): SigninState => { // export const reducer: reducer = (state: SigninState = signinDefaultState, action: Action<Member | Error>): SigninState => {
// switch (action.type) { // switch (action.type) {