├── .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 |
39 |

Redux Patterns

40 |
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 | {volumeInfo.title} 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 | ); --------------------------------------------------------------------------------