├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── assets
│ └── app.css
├── components
│ ├── App.js
│ ├── Books.js
│ ├── OrderBook.js
│ └── Spinner.js
├── index.js
└── redux
│ ├── reducers
│ ├── books.js
│ ├── index.js
│ ├── order.js
│ └── ui.js
│ └── store.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | .idea
6 |
7 | # testing
8 | /coverage
9 |
10 | # production
11 | /build
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
2 |
3 | ````
4 | yarn & yarn start
5 | ````
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "redux-patterns",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "json-server": "^0.12.1",
7 | "milligram": "^1.3.0",
8 | "react": "^16.2.0",
9 | "react-dom": "^16.2.0",
10 | "react-redux": "^5.0.6",
11 | "react-scripts": "1.1.0",
12 | "redux": "^3.7.2"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test --env=jsdom",
18 | "eject": "react-scripts eject"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/demo-projects/redux-patterns-demo/269cb1d32c1fdbfb21397f94d6374f8b7e5d2f70/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/assets/app.css:
--------------------------------------------------------------------------------
1 | .app-wrapper {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | }
6 |
7 | .books-wrapper {
8 | display: flex;
9 | flex-direction: column;
10 | justify-content: space-around;
11 | flex-wrap: wrap
12 | }
13 |
14 | .book {
15 | display: flex;
16 | flex-direction: column;
17 | align-items: center;
18 | padding: 5px;
19 | }
20 |
21 | .spinner{
22 | pointer-events: none;
23 | width: 3em;
24 | height: 3em;
25 | border: 0.4em solid #eee;
26 | border-top-color: #9b4dca;
27 | border-radius: 50%;
28 | -webkit-animation: loadingspin 1s linear infinite;
29 | animation: loadingspin 1s linear infinite;
30 | }
31 |
32 | @-webkit-keyframes loadingspin {
33 | 100% {
34 | -webkit-transform: rotate(360deg);
35 | transform: rotate(360deg);
36 | }
37 | }
38 |
39 | @keyframes loadingspin {
40 | 100% {
41 | -webkit-transform: rotate(360deg);
42 | transform: rotate(360deg);
43 | }
44 | }
--------------------------------------------------------------------------------
/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Books} from "./Books";
3 | import {OrderBook} from "./OrderBook";
4 | import {Spinner} from './Spinner';
5 | import {connect} from "react-redux";
6 |
7 | const API = 'https://www.googleapis.com/books/v1/volumes?q=react';
8 |
9 | class App extends Component {
10 |
11 | state = {books: []};
12 |
13 | componentWillMount() {
14 | fetch(API).then(result => result.json())
15 | .then(result => this.setState({books: result.items}))
16 | }
17 |
18 | selectBook = (bookId) => {
19 | console.log(bookId);
20 | };
21 |
22 | handleOrder = (email) => {
23 | console.log(email);
24 | };
25 |
26 | renderContent = () => {
27 | const {orderInProcess} = this.props;
28 |
29 | return orderInProcess ?
30 | :
31 | };
32 |
33 | render() {
34 | const {pending} = this.props;
35 |
36 | return (
37 |
38 |
41 |
42 | {pending && }
43 |
44 | {this.renderContent()}
45 |
46 |
47 | );
48 | }
49 | }
50 |
51 | const mapStateToProps = state => ({
52 | pending : state.ui.pending,
53 | orderInProcess: state.ui.orderInProcess,
54 | books : state.books,
55 | order : state.order
56 | });
57 |
58 | export default connect(mapStateToProps)(App);
59 |
--------------------------------------------------------------------------------
/src/components/Books.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const Books = ({books, onSelect}) => (
4 |
5 | { books.map( ({ volumeInfo, id }) => (
6 |
onSelect(id)}>
7 |

8 |
{volumeInfo.title}
9 |
{volumeInfo.authors[0]}
10 |
11 | ))}
12 |
13 | );
14 |
--------------------------------------------------------------------------------
/src/components/OrderBook.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const OrderBook = ({ onPlaceOrder }) => (
4 |
5 |
book image
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/src/components/Spinner.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const Spinner = () =>
4 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 |
5 | import 'milligram/dist/milligram.css';
6 | import './assets/app.css';
7 |
8 | import App from './components/App';
9 | import {store} from "./redux/store";
10 |
11 | ReactDOM.render(
12 |
13 |
14 | ,
15 | document.getElementById('root'));
16 |
17 |
--------------------------------------------------------------------------------
/src/redux/reducers/books.js:
--------------------------------------------------------------------------------
1 | export function booksReducer(books = [], action) {
2 | return books;
3 | }
--------------------------------------------------------------------------------
/src/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from "redux";
2 | import {booksReducer} from "./books";
3 | import {uiReducer} from "./ui";
4 | import {orderReducer} from "./order";
5 |
6 | export const reducers = combineReducers({
7 | ui : uiReducer,
8 | books: booksReducer,
9 | order: orderReducer
10 | });
11 |
--------------------------------------------------------------------------------
/src/redux/reducers/order.js:
--------------------------------------------------------------------------------
1 | const initOrder = {
2 | bookId: null,
3 | email: ''
4 | };
5 |
6 | export function orderReducer(order = initOrder, action) {
7 | console.log('books order');
8 | return order;
9 | }
10 |
--------------------------------------------------------------------------------
/src/redux/reducers/ui.js:
--------------------------------------------------------------------------------
1 | const initUi = {
2 | pending: false,
3 | orderInProcess: false
4 | };
5 |
6 | export function uiReducer (state = initUi, action) {
7 | console.log('ui reducer');
8 | return state;
9 | }
--------------------------------------------------------------------------------
/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import {applyMiddleware, createStore, compose} from "redux";
2 | import {reducers} from "./reducers";
3 |
4 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
5 |
6 | export const store = createStore(
7 | reducers,
8 | composeEnhancers(
9 | applyMiddleware(),
10 | )
11 | );
--------------------------------------------------------------------------------