Skip to content

Commit 6d5f05d

Browse files
committed
Init
0 parents  commit 6d5f05d

File tree

15 files changed

+383
-0
lines changed

15 files changed

+383
-0
lines changed

.babelrc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"presets": [
3+
["es2015", {"modules": false}],
4+
// webpack understands the native import syntax, and uses it for tree shaking
5+
6+
"react"
7+
// Transpile React components to JavaScript
8+
],
9+
"plugins": [
10+
"react-hot-loader/babel"
11+
// Enables React code to work with HMR.
12+
]
13+
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
build

dist/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Webpack2 + React + Redux + React Router 4 by KK</title>
6+
</head>
7+
<body>
8+
<div id="root"></div>
9+
10+
<script src="bundle.js"></script>
11+
</body>
12+
</html>

package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "webpack2",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"start": "webpack-dev-server"
9+
},
10+
"keywords": [],
11+
"author": "Kyryll Kozak <[email protected]>",
12+
"license": "ISC",
13+
"devDependencies": {
14+
"babel-core": "^6.24.1",
15+
"babel-loader": "^7.0.0",
16+
"babel-preset-es2015": "^6.24.1",
17+
"babel-preset-react": "^6.24.1",
18+
"css-loader": "^0.28.1",
19+
"style-loader": "^0.17.0",
20+
"webpack": "^2.5.1",
21+
"webpack-dev-server": "^2.4.5",
22+
"wepback": "^1.0.0"
23+
},
24+
"dependencies": {
25+
"axios": "^0.16.1",
26+
"prop-types": "^15.5.8",
27+
"react": "^15.5.4",
28+
"react-dom": "^15.5.4",
29+
"react-hot-loader": "^3.0.0-beta.7",
30+
"react-redux": "^5.0.4",
31+
"react-router-dom": "^4.1.1",
32+
"react-thunk": "^1.0.0",
33+
"redux": "^3.6.0",
34+
"redux-promise-middleware": "^4.2.0",
35+
"redux-thunk": "^2.2.0"
36+
}
37+
}

src/actions/appActions.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { fetchNewValue } from "./../utils/fetchData";
2+
3+
export const RECEIVE_VALUE_PENDING = "RECEIVE_VALUE_PENDING";
4+
export const RECEIVE_VALUE_FULFILLED = "RECEIVE_VALUE_FULFILLED";
5+
export const RECEIVE_VALUE_REJECTED = "RECEIVE_VALUE_REJECTED";
6+
7+
const pendingValue = () => ({
8+
type: RECEIVE_VALUE_PENDING
9+
});
10+
11+
const receiveValue = (result) => ({
12+
type: RECEIVE_VALUE_FULFILLED,
13+
payload: result
14+
});
15+
16+
const rejectValue = (error) => ({
17+
type: RECEIVE_VALUE_REJECTED,
18+
payload: error
19+
});
20+
21+
export const getNewValue = () => {
22+
return function (dispatch) {
23+
dispatch(pendingValue());
24+
25+
fetchNewValue()
26+
.then((response) => {
27+
let {data} = response;
28+
29+
dispatch(receiveValue(data));
30+
})
31+
.catch((error) => {
32+
console.log(error);
33+
34+
dispatch(rejectValue(error));
35+
});
36+
};
37+
};

src/components/App/App.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.app {
2+
text-size-adjust: none;
3+
font-family: helvetica, arial, sans-serif;
4+
line-height: 200%;
5+
padding: 6px 20px 30px;
6+
color: green;
7+
}

src/components/App/App.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React, {Component} from "react";
2+
import PropTypes from "prop-types"; // ES6
3+
4+
import styles from "./App.css";
5+
6+
class App extends Component {
7+
render() {
8+
return (
9+
<div className={styles.app}>
10+
<h1>Key: {this.props.value}</h1>
11+
<button onClick={this.props.onClick}>Change value</button>
12+
</div>
13+
);
14+
}
15+
}
16+
17+
App.propTypes = {
18+
value: PropTypes.string.isRequired,
19+
onClick: PropTypes.func.isRequired
20+
};
21+
22+
export default App;

src/containers/App/AppContainer.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, {Component} from "react";
2+
3+
import {connect} from "react-redux";
4+
5+
import App from "../../components/App/App";
6+
7+
import {getNewValue} from "../../actions/appActions";
8+
9+
class AppContainer extends Component {
10+
constructor(props) {
11+
super(props);
12+
13+
this.handleClick = this.handleClick.bind(this);
14+
}
15+
16+
handleClick() {
17+
this.props.dispatch(getNewValue());
18+
}
19+
20+
render() {
21+
const {fetching, fetched, error, key} = this.props.app;
22+
23+
return (
24+
<App onClick={this.handleClick} value={key} />
25+
);
26+
}
27+
}
28+
29+
const mapStateToProps = (state) => {
30+
return {
31+
app: state.app
32+
};
33+
};
34+
35+
export default connect(mapStateToProps)(AppContainer);

src/index.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from "react";
2+
import ReactDOM from "react-dom";
3+
import { Provider } from "react-redux";
4+
5+
import { AppContainer } from "react-hot-loader";
6+
7+
import Routes from "./routes";
8+
import store from "./store";
9+
10+
const render = (Component) => {
11+
ReactDOM.render(
12+
<AppContainer>
13+
<Provider store={store}>
14+
<Routes />
15+
</Provider>
16+
</AppContainer>,
17+
18+
document.getElementById("root")
19+
);
20+
};
21+
22+
render();
23+
24+
// // Hot Module Replacement API
25+
// if (module.hot) {
26+
// module.hot.accept("./components/App", () => {
27+
// render();
28+
// });
29+
// }

src/reducers/appReducer.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"use strict";
2+
3+
import {RECEIVE_VALUE_PENDING, RECEIVE_VALUE_FULFILLED, RECEIVE_VALUE_REJECTED} from "../actions/appActions";
4+
5+
const INIT={
6+
key: "null",
7+
8+
fetching: false,
9+
fetched: false,
10+
11+
error: ""
12+
};
13+
14+
export default function reducer(state = INIT, action) {
15+
switch (action.type) {
16+
case RECEIVE_VALUE_PENDING: {
17+
state = Object.assign({}, state, {fetched: false, fetching: true});
18+
19+
break;
20+
}
21+
22+
case RECEIVE_VALUE_FULFILLED: {
23+
console.log(action);
24+
25+
state = Object.assign({}, state, {fetched: true, fetching: false, key: action.payload});
26+
27+
break;
28+
}
29+
30+
case RECEIVE_VALUE_REJECTED: {
31+
state = Object.assign({}, state, {fetched: false, fetching: false, error: action.payload});
32+
33+
break;
34+
}
35+
}
36+
37+
return state;
38+
};

src/reducers/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {combineReducers} from "redux";
2+
3+
import app from "./appReducer";
4+
5+
const stores = combineReducers({
6+
app
7+
});
8+
9+
export default stores;

src/routes.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from "react";
2+
3+
import {
4+
HashRouter as Router,
5+
Route,
6+
Link
7+
} from "react-router-dom";
8+
9+
import App from "./containers/App/AppContainer";
10+
11+
const About = () => (
12+
<div>
13+
<h2>About</h2>
14+
</div>
15+
);
16+
17+
const Routes = () => (
18+
<Router>
19+
<div>
20+
<ul>
21+
<li><Link to="/">Home</Link></li>
22+
<li><Link to="/about">About</Link></li>
23+
</ul>
24+
25+
<hr/>
26+
27+
<Route exact path="/" component={App}/>
28+
<Route path="/about" component={About}/>
29+
</div>
30+
</Router>
31+
);
32+
33+
export default Routes;

src/store.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {createStore, applyMiddleware} from "redux";
2+
import thunk from "redux-thunk";
3+
import promise from "redux-promise-middleware";
4+
5+
import reducers from "./reducers";
6+
7+
let env = process.env.NODE_ENV;
8+
9+
let middleware, store, composeEnhancers;
10+
11+
if (env === "developer") {
12+
middleware = applyMiddleware(promise(), thunk);
13+
14+
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
15+
16+
store = createStore(reducers, composeEnhancers(
17+
middleware
18+
));
19+
} else {
20+
middleware = applyMiddleware(promise(), thunk);
21+
22+
store = createStore(reducers, middleware);
23+
}
24+
25+
export default store;

src/utils/fetchData.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"use strict";
2+
3+
export const fetchNewValue = () => {
4+
const getRandomInt = (min=1, max=100) => Math.floor(Math.random() * (max - min)) + min;
5+
6+
return new Promise((resolve, reject) => {
7+
let value = getRandomInt();
8+
9+
console.log(value);
10+
11+
// Simulate fake loading
12+
setTimeout(() => {
13+
resolve({
14+
data: String(value)
15+
});
16+
}, 300);
17+
});
18+
};

0 commit comments

Comments
 (0)