import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {createStore, combineReducers, applyMiddleware, Dispatch, Reducer} from 'redux';
import {Provider, connect} from 'react-redux';
import * as logger from 'redux-logger';
import thunk from 'redux-thunk';
// Action types
type TCounterUp = 'COUNTER_UP';
type TCounterDown = 'COUNTER_DOWN';
const COUNTER_UP: TCounterUp = 'COUNTER_UP';
const COUNTER_DOWN: TCounterDown = 'COUNTER_DOWN';
// Actions
type TCouterUpAction = {
type: TCounterUp,
value: number
};
type TCouterDownAction = {
type: TCounterDown,
value: number
};
type TCounterAction = TCouterUpAction
| TCouterDownAction;
const couterUpAction = (value: number): TCouterUpAction => {
return {
type: COUNTER_UP,
value: value
};
};
const couterDownAction = (value: number): TCouterDownAction => {
return {
type: COUNTER_DOWN,
value: value
};
};
const couterDownAsync = (value: number) => {
return function (dispatch: Dispatch<any>): void {
setTimeout((): void => {
dispatch(couterDownAction(value));
}, 1000);
};
};
// Reducers
interface ICounterState {
value: number;
}
const defaultCounterState: ICounterState = {value: 0};
const counterReducer = (state: ICounterState = defaultCounterState, action: TCounterAction): ICounterState => {
switch (action.type) {
case COUNTER_UP: return Object.assign({}, state, {value: state.value + action.value});
case COUNTER_DOWN: return Object.assign({}, state, {value: state.value - action.value});
default: return state;
}
};
const outterReducer: Reducer<any> = combineReducers({
inner: counterReducer
});
const rootReducer: Reducer<any> = combineReducers({
counter: outterReducer
});
// Store
const initialStoreState: Object = {
counter: {
inner: {
value: 0
}
}
};
const store = createStore(rootReducer, initialStoreState, applyMiddleware((logger as any).createLogger(), thunk));
// Interfaces
interface IStateProps {
counter: number;
}
interface IDispatchProps {
handleUpClick: () => void;
handleDownClick: () => void;
}
interface IOwnProps {
myProp: number;
}
type IProps = IStateProps & IDispatchProps & IOwnProps;
interface IState {}
// Component
class MyComponent extends React.Component<IProps, IStateProps> {
constructor (props) {
super(props);
}
render (): JSX.Element {
const {
myProp,
counter,
handleUpClick,
handleDownClick
} = this.props;
return (
<div>
<div>Моё свойство: {myProp}</div>
<span>{counter}</span>{' '}
<span onClick={handleUpClick}>Вверх</span>{' '}
<span onClick={handleDownClick}>Вниз</span>
</div>
);
}
}
// Connect
const mapStateToProps = (state: any, ownProps: IOwnProps): IStateProps => {
return {
counter: state.counter.inner.value
};
};
const mapDispatchToProps = (dispatch: Dispatch<any>, ownProps: IOwnProps): IDispatchProps => {
return {
handleUpClick: (): void => {
dispatch(couterUpAction(1));
},
handleDownClick: (): void => {
dispatch(couterDownAsync(1));
}
};
};
const ConnectedMyComponent = connect<IStateProps, IDispatchProps, IOwnProps>(mapStateToProps, mapDispatchToProps)(MyComponent);
interface IRootComponentProps {}
interface IRootComponentState {}
class RootComponent extends React.Component<IRootComponentProps, IRootComponentState> {
render (): JSX.Element {
return (
<ConnectedMyComponent myProp={123} />
);
}
}
ReactDOM.render(<Provider store={store}><RootComponent /></Provider>, document.getElementById('root'));
Комментариев нет:
Отправить комментарий