├── src ├── index.css ├── actions │ ├── types.js │ └── postActions.js ├── reducers │ ├── index.js │ └── postReducer.js ├── index.js ├── App.test.js ├── store.js ├── App.css ├── App.js ├── components │ ├── Posts.js │ └── Postform.js ├── logo.svg └── registerServiceWorker.js ├── public ├── favicon.ico ├── manifest.json └── index.html ├── README.md ├── .gitignore └── package.json /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradtraversy/redux_crash_course/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/actions/types.js: -------------------------------------------------------------------------------- 1 | export const FETCH_POSTS = 'FETCH_POSTS'; 2 | export const NEW_POST = 'NEW_POST'; 3 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import postReducer from './postReducer'; 3 | 4 | export default combineReducers({ 5 | posts: postReducer 6 | }); 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redux Crash Course 2 | 3 | > Code from the "Redux Crash Course With React" video. Simple implementation of Redux using a couple React components. 4 | 5 | ## Quick Start 6 | 7 | ```bash 8 | # Install dependencies 9 | npm install 10 | 11 | # Serve on localhost:3000 12 | npm start 13 | ``` 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /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/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import rootReducer from './reducers'; 4 | 5 | const initialState = {}; 6 | 7 | const middleware = [thunk]; 8 | 9 | const store = createStore( 10 | rootReducer, 11 | initialState, 12 | compose( 13 | applyMiddleware(...middleware), 14 | window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() 15 | ) 16 | ); 17 | 18 | export default store; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reduxexample", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.2.0", 7 | "react-dom": "^16.2.0", 8 | "react-redux": "^5.0.7", 9 | "react-scripts": "1.1.1", 10 | "redux": "^3.7.2", 11 | "redux-thunk": "^2.2.0" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/reducers/postReducer.js: -------------------------------------------------------------------------------- 1 | import { FETCH_POSTS, NEW_POST } from '../actions/types'; 2 | 3 | const initialState = { 4 | items: [], 5 | item: {} 6 | }; 7 | 8 | export default function(state = initialState, action) { 9 | switch (action.type) { 10 | case FETCH_POSTS: 11 | return { 12 | ...state, 13 | items: action.payload 14 | }; 15 | case NEW_POST: 16 | return { 17 | ...state, 18 | item: action.payload 19 | }; 20 | default: 21 | return state; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | width: 90%; 3 | margin: auto; 4 | } 5 | 6 | .App-logo { 7 | animation: App-logo-spin infinite 20s linear; 8 | height: 80px; 9 | } 10 | 11 | .App-header { 12 | background-color: #222; 13 | height: 150px; 14 | padding: 20px; 15 | color: white; 16 | } 17 | 18 | .App-title { 19 | font-size: 1.5em; 20 | } 21 | 22 | .App-intro { 23 | font-size: large; 24 | } 25 | 26 | @keyframes App-logo-spin { 27 | from { 28 | transform: rotate(0deg); 29 | } 30 | to { 31 | transform: rotate(360deg); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/actions/postActions.js: -------------------------------------------------------------------------------- 1 | import { FETCH_POSTS, NEW_POST } from './types'; 2 | 3 | export const fetchPosts = () => dispatch => { 4 | fetch('https://jsonplaceholder.typicode.com/posts') 5 | .then(res => res.json()) 6 | .then(posts => 7 | dispatch({ 8 | type: FETCH_POSTS, 9 | payload: posts 10 | }) 11 | ); 12 | }; 13 | 14 | export const createPost = postData => dispatch => { 15 | fetch('https://jsonplaceholder.typicode.com/posts', { 16 | method: 'POST', 17 | headers: { 18 | 'content-type': 'application/json' 19 | }, 20 | body: JSON.stringify(postData) 21 | }) 22 | .then(res => res.json()) 23 | .then(post => 24 | dispatch({ 25 | type: NEW_POST, 26 | payload: post 27 | }) 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | import { Provider } from 'react-redux'; 5 | 6 | import Posts from './components/Posts'; 7 | import PostForm from './components/Postform'; 8 | 9 | import store from './store'; 10 | 11 | class App extends Component { 12 | render() { 13 | return ( 14 | 15 |
16 |
17 | logo 18 |

Welcome to React

19 |
20 | 21 |
22 | 23 |
24 |
25 | ); 26 | } 27 | } 28 | 29 | export default App; 30 | -------------------------------------------------------------------------------- /src/components/Posts.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import { fetchPosts } from '../actions/postActions'; 5 | 6 | class Posts extends Component { 7 | componentWillMount() { 8 | this.props.fetchPosts(); 9 | } 10 | 11 | componentWillReceiveProps(nextProps) { 12 | if (nextProps.newPost) { 13 | this.props.posts.unshift(nextProps.newPost); 14 | } 15 | } 16 | 17 | render() { 18 | const postItems = this.props.posts.map(post => ( 19 |
20 |

{post.title}

21 |

{post.body}

22 |
23 | )); 24 | return ( 25 |
26 |

Posts

27 | {postItems} 28 |
29 | ); 30 | } 31 | } 32 | 33 | Posts.propTypes = { 34 | fetchPosts: PropTypes.func.isRequired, 35 | posts: PropTypes.array.isRequired, 36 | newPost: PropTypes.object 37 | }; 38 | 39 | const mapStateToProps = state => ({ 40 | posts: state.posts.items, 41 | newPost: state.posts.item 42 | }); 43 | 44 | export default connect(mapStateToProps, { fetchPosts })(Posts); 45 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/components/Postform.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import { createPost } from '../actions/postActions'; 5 | 6 | class PostForm extends Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = { 10 | title: '', 11 | body: '' 12 | }; 13 | 14 | this.onChange = this.onChange.bind(this); 15 | this.onSubmit = this.onSubmit.bind(this); 16 | } 17 | 18 | onChange(e) { 19 | this.setState({ [e.target.name]: e.target.value }); 20 | } 21 | 22 | onSubmit(e) { 23 | e.preventDefault(); 24 | 25 | const post = { 26 | title: this.state.title, 27 | body: this.state.body 28 | }; 29 | 30 | this.props.createPost(post); 31 | } 32 | 33 | render() { 34 | return ( 35 |
36 |

Add Post

37 |
38 |
39 | 40 |
41 | 47 |
48 |
49 |
50 | 51 |
52 |