Skip to content

Commit 62bd8bd

Browse files
committed
feat: redux integration and example
1 parent ff5e0d2 commit 62bd8bd

File tree

10 files changed

+281
-4
lines changed

10 files changed

+281
-4
lines changed

react/globals.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@
77
declare module '*.svg'
88
declare module '*.png'
99
declare module '*.jpg'
10+
11+
// window.__REDUX_DEVTOOLS_EXTENSION__, for redux dev tools compatibility
12+
declare interface Window {
13+
__REDUX_DEVTOOLS_EXTENSION__: any,
14+
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: any
15+
}

react/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
"react": "^16.3.1",
2828
"react-dev-utils": "4.2.1",
2929
"react-dom": "^16.3.1",
30+
"react-redux": "^5.0.7",
31+
"redux": "^3.7.2",
32+
"redux-logger": "^3.0.6",
33+
"redux-thunk": "^2.2.0",
3034
"source-map-loader": "^0.2.1",
3135
"style-loader": "0.19.0",
3236
"sw-precache-webpack-plugin": "0.11.4",
@@ -35,6 +39,7 @@
3539
"tsconfig-paths-webpack-plugin": "^2.0.0",
3640
"tslint": "^5.7.0",
3741
"tslint-react": "^3.2.0",
42+
"typesafe-actions": "^1.1.2",
3843
"uglifyjs-webpack-plugin": "^1.1.8",
3944
"url-loader": "0.6.2",
4045
"webpack": "3.8.1",
@@ -61,6 +66,8 @@
6166
"@types/node": "^9.6.2",
6267
"@types/react": "^16.3.5",
6368
"@types/react-dom": "^16.0.4",
69+
"@types/react-redux": "^5.0.15",
70+
"@types/redux-logger": "^3.0.5",
6471
"concurrently": "^3.5.1",
6572
"serve": "^6.5.3",
6673
"tslint-config-prettier": "^1.10.0",

react/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import Counter from './components/counter';
23
import './App.css';
34

45
import logo from './logo.svg';
@@ -14,6 +15,7 @@ class App extends React.Component {
1415
<p className="App-intro">
1516
To get started, edit <code>src/App.tsx</code> and save to reload.
1617
</p>
18+
<Counter />
1719
</div>
1820
);
1921
}

react/src/components/counter.tsx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import * as React from 'react';
2+
import { connect } from 'react-redux';
3+
import { bindActionCreators } from 'redux';
4+
import { ActionCreators as Actions, IState } from '../modules';
5+
6+
interface ICounterProps {
7+
counter: number,
8+
increment(): void,
9+
decrement(): void,
10+
reset(): void,
11+
add(amount: number): void,
12+
sub(amount: number): void,
13+
};
14+
15+
class CounterComponent extends React.Component<ICounterProps, any> {
16+
constructor(props: any) {
17+
super(props);
18+
19+
this.state = {
20+
inputVal: 5
21+
}
22+
23+
this.props = props;
24+
25+
this.handleValueChange = this.handleValueChange.bind(this);
26+
this.add = this.add.bind(this);
27+
this.sub = this.sub.bind(this);
28+
}
29+
30+
handleValueChange(event: any) {
31+
this.setState({ inputVal: event.target.value });
32+
}
33+
34+
add() {
35+
this.props.add(this.state.inputVal);
36+
}
37+
38+
sub() {
39+
this.props.sub(this.state.inputVal);
40+
}
41+
42+
render() {
43+
return (
44+
<div>
45+
<p>{this.props.counter}</p>
46+
<p>
47+
<button onClick={this.props.decrement}>-</button>
48+
&nbsp;|&nbsp;
49+
<button onClick={this.props.increment}>+</button>
50+
</p>
51+
<p><button onClick={this.props.reset}>Reset</button></p>
52+
<p>
53+
<input type="number" value={this.state.inputVal} onChange={this.handleValueChange} />
54+
</p>
55+
<p>
56+
<button onClick={this.add}>Add {this.state.inputVal} to counter</button>&nbsp;
57+
<button onClick={this.sub}>Subtract {this.state.inputVal} from counter</button>
58+
</p>
59+
</div>
60+
)
61+
}
62+
}
63+
64+
const mapStateToProps = (state: IState) => ({
65+
counter: state.example.counter
66+
});
67+
68+
const mapDispatchToProps = (dispatch: any) => (
69+
bindActionCreators({
70+
increment: Actions.example.incrementCounter,
71+
decrement: Actions.example.decrementCounter,
72+
reset: Actions.example.resetCounter,
73+
add: Actions.example.addToCounter,
74+
sub: Actions.example.subtractFromCounter,
75+
}, dispatch)
76+
);
77+
78+
const Counter = connect(mapStateToProps, mapDispatchToProps)(CounterComponent);
79+
80+
export default Counter;

react/src/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import * as React from 'react';
22
import * as ReactDOM from 'react-dom';
3+
import { Provider } from 'react-redux';
34
import App from './App';
45
import registerServiceWorker from './registerServiceWorker';
6+
import store from './utils/store';
57
import './index.css';
68

79
ReactDOM.render(
8-
<App />,
10+
(<Provider store={store}>
11+
<App />
12+
</Provider>),
913
document.getElementById('root') as HTMLElement
1014
);
15+
1116
registerServiceWorker();

react/src/modules/example.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { createAction } from 'typesafe-actions';
2+
3+
export interface IExampleState {
4+
readonly counter: number,
5+
};
6+
7+
export enum Actions {
8+
IncrementCounter = 'INCREMENT_COUNTER',
9+
DecrementCounter = 'DECREMENT_COUNTER',
10+
AddToCounter = 'ADD_TO_COUNTER',
11+
SubtractFromCounter = 'SUBTRACT_FROM_COUNTER',
12+
ResetCounter = 'RESET_COUNTER'
13+
};
14+
15+
const incrementCounter = createAction(Actions.IncrementCounter);
16+
17+
const decrementCounter = createAction(Actions.DecrementCounter);
18+
19+
const addToCounter = createAction(Actions.AddToCounter, (amount: number) => ({
20+
type: Actions.AddToCounter,
21+
payload: amount,
22+
}));
23+
24+
const subtractFromCounter = createAction(Actions.SubtractFromCounter, (amount: number) => ({
25+
type: Actions.SubtractFromCounter,
26+
payload: amount,
27+
}));
28+
29+
const resetCounter = createAction(Actions.ResetCounter);
30+
31+
export const ActionCreators = {
32+
incrementCounter,
33+
decrementCounter,
34+
addToCounter,
35+
subtractFromCounter,
36+
resetCounter,
37+
};
38+
39+
const initialState: IExampleState = {
40+
counter: 0,
41+
};
42+
43+
const example = (state: IExampleState = initialState, action: any) => {
44+
switch(action.type) {
45+
case Actions.IncrementCounter: {
46+
const counter = state.counter + 1;
47+
return { counter };
48+
}
49+
case Actions.DecrementCounter: {
50+
const counter = state.counter - 1;
51+
return { counter };
52+
}
53+
case Actions.AddToCounter: {
54+
const counter = state.counter + Number(action.payload);
55+
return { counter };
56+
}
57+
case Actions.SubtractFromCounter: {
58+
const counter = state.counter - Number(action.payload);
59+
return { counter };
60+
}
61+
case Actions.ResetCounter: {
62+
return { counter: 0 };
63+
}
64+
default:
65+
return state;
66+
}
67+
}
68+
69+
export default example;

react/src/modules/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { combineReducers } from 'redux';
2+
import example, {
3+
Actions as ExampleActions,
4+
ActionCreators as ExampleActionCreators,
5+
IExampleState,
6+
} from './example';
7+
8+
const reducers = combineReducers({
9+
example,
10+
});
11+
12+
export default reducers;
13+
14+
export const Actions = {
15+
example: ExampleActions
16+
};
17+
18+
export const ActionCreators = {
19+
example: ExampleActionCreators
20+
}
21+
22+
export interface IState {
23+
example: IExampleState
24+
};

react/src/utils/store.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { applyMiddleware, compose, createStore } from 'redux';
2+
import { createLogger } from 'redux-logger';
3+
import thunkMiddleware from 'redux-thunk';
4+
import reducers from '../modules';
5+
6+
const middlewares: any[] = [thunkMiddleware];
7+
8+
if (process.env.NODE_ENV === 'development') {
9+
const loggerMiddleware = createLogger();
10+
middlewares.push(loggerMiddleware);
11+
}
12+
13+
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
14+
15+
const middleware = composeEnhancers(applyMiddleware(...middlewares));
16+
17+
const store = createStore(reducers, middleware);
18+
19+
export default store;

react/tslint.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
},
99
"rules": {
1010
"member-access": false,
11-
"ordered-imports": false
11+
"ordered-imports": false,
12+
"object-literal-sort-keys": false,
13+
"no-console": false
1214
}
1315
}

0 commit comments

Comments
 (0)