├── .nvmrc ├── 6-mobx-react ├── .nvmrc ├── .gitignore ├── .babelrc ├── src │ ├── index.html │ ├── js │ │ ├── main.js │ │ ├── TodoStore.js │ │ └── TodoList.js │ └── css │ │ └── main.css ├── package.json └── webpack.config.js ├── .gitignore ├── 3-flux ├── src │ ├── js │ │ ├── dispatcher.js │ │ ├── pages │ │ │ ├── Favorites.js │ │ │ ├── Settings.js │ │ │ ├── Layout.js │ │ │ └── Todos.js │ │ ├── components │ │ │ ├── layout │ │ │ │ ├── Footer.js │ │ │ │ └── Nav.js │ │ │ └── Todo.js │ │ ├── client.js │ │ ├── actions │ │ │ └── TodoActions.js │ │ └── stores │ │ │ └── TodoStore.js │ └── index.html ├── package.json └── webpack.config.js ├── 4-redux ├── src │ ├── js │ │ ├── components │ │ │ ├── Footer.js │ │ │ ├── Header │ │ │ │ └── Title.js │ │ │ ├── Header.js │ │ │ └── Layout.js │ │ ├── 1-basic-setup.js │ │ ├── client.js │ │ ├── 4-async-middleware.js │ │ ├── 3-middleware.js │ │ └── 2-multiple-reducers.js │ └── index.html ├── webpack.config.js └── package.json ├── 1-basic-react ├── src │ ├── js │ │ ├── client.js │ │ └── components │ │ │ ├── Footer.js │ │ │ ├── Header │ │ │ └── Title.js │ │ │ ├── Header.js │ │ │ └── Layout.js │ └── index.html ├── README.md ├── package.json └── webpack.config.js ├── 5-redux-react ├── src │ ├── js │ │ ├── reducers │ │ │ ├── index.js │ │ │ ├── userReducer.js │ │ │ └── tweetsReducer.js │ │ ├── client.js │ │ ├── store.js │ │ ├── actions │ │ │ ├── userActions.js │ │ │ └── tweetsActions.js │ │ └── components │ │ │ └── Layout.js │ └── index.html ├── webpack.config.js └── package.json └── 2-react-router ├── src ├── js │ ├── pages │ │ ├── Settings.js │ │ ├── Layout.js │ │ ├── Archives.js │ │ └── Featured.js │ ├── components │ │ ├── layout │ │ │ ├── Footer.js │ │ │ └── Nav.js │ │ └── Article.js │ └── client.js └── index.html ├── package.json └── webpack.config.js /.nvmrc: -------------------------------------------------------------------------------- 1 | v5.4.0 2 | -------------------------------------------------------------------------------- /6-mobx-react/.nvmrc: -------------------------------------------------------------------------------- 1 | v6.3.0 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /6-mobx-react/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /3-flux/src/js/dispatcher.js: -------------------------------------------------------------------------------- 1 | import { Dispatcher } from "flux"; 2 | 3 | export default new Dispatcher; 4 | -------------------------------------------------------------------------------- /6-mobx-react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ['react', 'es2015'], 3 | "plugins": ['transform-decorators-legacy', 'transform-class-properties'] 4 | } 5 | -------------------------------------------------------------------------------- /4-redux/src/js/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | export default class Footer extends React.Component { 5 | render() { 6 | return ( 7 | 8 | ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /1-basic-react/src/js/client.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | 4 | import Layout from "./components/Layout"; 5 | 6 | const app = document.getElementById('app'); 7 | ReactDOM.render(, app); 8 | -------------------------------------------------------------------------------- /1-basic-react/src/js/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | export default class Footer extends React.Component { 5 | render() { 6 | return ( 7 | 8 | ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /4-redux/src/js/components/Header/Title.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | export default class Title extends React.Component { 5 | render() { 6 | return ( 7 |

{this.props.title}

8 | ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /1-basic-react/src/js/components/Header/Title.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | export default class Title extends React.Component { 5 | render() { 6 | return ( 7 |

{this.props.title}

8 | ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /5-redux-react/src/js/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux" 2 | 3 | import tweets from "./tweetsReducer" 4 | import user from "./userReducer" 5 | 6 | export default combineReducers({ 7 | tweets, 8 | user, 9 | }) 10 | -------------------------------------------------------------------------------- /3-flux/src/js/pages/Favorites.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default class Archives extends React.Component { 4 | render() { 5 | return ( 6 |
7 |

Favorites

8 |
9 | ); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /3-flux/src/js/pages/Settings.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default class Settings extends React.Component { 4 | render() { 5 | return ( 6 |
7 |

Settings

8 |
9 | ); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /2-react-router/src/js/pages/Settings.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default class Settings extends React.Component { 4 | render() { 5 | console.log("settings"); 6 | return ( 7 |

Settings

8 | ); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /6-mobx-react/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /6-mobx-react/src/js/main.js: -------------------------------------------------------------------------------- 1 | import "../css/main.css" 2 | import React from "react" 3 | import ReactDOM from "react-dom" 4 | import TodoStore from "./TodoStore" 5 | import TodoList from "./TodoList" 6 | 7 | const app = document.getElementById("app") 8 | 9 | ReactDOM.render(, app) 10 | 11 | -------------------------------------------------------------------------------- /5-redux-react/src/js/client.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import ReactDOM from "react-dom" 3 | import { Provider } from "react-redux" 4 | 5 | import Layout from "./components/Layout" 6 | import store from "./store" 7 | 8 | const app = document.getElementById('app') 9 | 10 | ReactDOM.render( 11 | 12 | , app); 13 | -------------------------------------------------------------------------------- /5-redux-react/src/js/store.js: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, createStore } from "redux" 2 | 3 | import logger from "redux-logger" 4 | import thunk from "redux-thunk" 5 | import promise from "redux-promise-middleware" 6 | 7 | import reducer from "./reducers" 8 | 9 | const middleware = applyMiddleware(promise(), thunk, logger()) 10 | 11 | export default createStore(reducer, middleware) 12 | -------------------------------------------------------------------------------- /2-react-router/src/js/components/layout/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | export default class Footer extends React.Component { 5 | render() { 6 | return ( 7 |
8 |
9 |
10 |

Copyright © KillerNews.net

11 |
12 |
13 |
14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4-redux/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Tutorials 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /1-basic-react/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Tutorials 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /5-redux-react/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Tutorials 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /5-redux-react/src/js/actions/userActions.js: -------------------------------------------------------------------------------- 1 | export function fetchUser() { 2 | return { 3 | type: "FETCH_USER_FULFILLED", 4 | payload: { 5 | name: "Will", 6 | age: 35, 7 | } 8 | } 9 | } 10 | 11 | export function setUserName(name) { 12 | return { 13 | type: 'SET_USER_NAME', 14 | payload: name, 15 | } 16 | } 17 | 18 | export function setUserAge(age) { 19 | return { 20 | type: 'SET_USER_AGE', 21 | payload: age, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /3-flux/src/js/components/layout/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | 4 | export default class Footer extends React.Component { 5 | render() { 6 | const footerStyles = { 7 | marginTop: "30px", 8 | }; 9 | 10 | return ( 11 |
12 |
13 |
14 |

Copyright © PerfectTodos.com

15 |
16 |
17 |
18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /4-redux/src/js/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Title from "./Header/Title"; 4 | 5 | export default class Header extends React.Component { 6 | handleChange(e) { 7 | const title = e.target.value; 8 | this.props.changeTitle(title); 9 | } 10 | 11 | render() { 12 | return ( 13 |
14 | 15 | <input value={this.props.title} onChange={this.handleChange.bind(this)} /> 16 | </div> 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /1-basic-react/src/js/components/Header.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Title from "./Header/Title"; 4 | 5 | export default class Header extends React.Component { 6 | handleChange(e) { 7 | const title = e.target.value; 8 | this.props.changeTitle(title); 9 | } 10 | 11 | render() { 12 | return ( 13 | <div> 14 | <Title title={this.props.title} /> 15 | <input value={this.props.title} onChange={this.handleChange.bind(this)} /> 16 | </div> 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /4-redux/src/js/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Footer from "./Footer"; 4 | import Header from "./Header"; 5 | 6 | export default class Layout extends React.Component { 7 | constructor() { 8 | super(); 9 | this.state = { 10 | title: "Welcome", 11 | }; 12 | } 13 | 14 | changeTitle(title) { 15 | this.setState({title}); 16 | } 17 | 18 | render() { 19 | return ( 20 | <div> 21 | <Header changeTitle={this.changeTitle.bind(this)} title={this.state.title} /> 22 | <Footer /> 23 | </div> 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /1-basic-react/src/js/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Footer from "./Footer"; 4 | import Header from "./Header"; 5 | 6 | export default class Layout extends React.Component { 7 | constructor() { 8 | super(); 9 | this.state = { 10 | title: "Welcome", 11 | }; 12 | } 13 | 14 | changeTitle(title) { 15 | this.setState({title}); 16 | } 17 | 18 | render() { 19 | return ( 20 | <div> 21 | <Header changeTitle={this.changeTitle.bind(this)} title={this.state.title} /> 22 | <Footer /> 23 | </div> 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /3-flux/src/js/components/Todo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default class Todo extends React.Component { 4 | constructor(props) { 5 | super(); 6 | } 7 | 8 | render() { 9 | const { complete, edit, text } = this.props; 10 | 11 | const icon = complete ? "\u2714" : "\u2716" 12 | 13 | if (edit) { 14 | return ( 15 | <li> 16 | <input value={text} focus="focused"/> 17 | </li> 18 | ); 19 | } 20 | 21 | return ( 22 | <li> 23 | <span>{text}</span> 24 | <span>{icon}</span> 25 | </li> 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /2-react-router/src/js/components/Article.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default class Article extends React.Component { 4 | render() { 5 | const { title } = this.props; 6 | 7 | return ( 8 | <div class="col-md-4"> 9 | <h4>{title}</h4> 10 | <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Saepe rem nisi accusamus error velit animi non ipsa placeat. Recusandae, suscipit, soluta quibusdam accusamus a veniam quaerat eveniet eligendi dolor consectetur.</p> 11 | <a class="btn btn-default" href="#">More Info</a> 12 | </div> 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /1-basic-react/README.md: -------------------------------------------------------------------------------- 1 | ## Instructions to run 2 | 1. Navigate to folder */1-basic-react* 3 | 2. *NPM install* 4 | 3. *NPM run dev* 5 | 4. Navigate to localhost:8080 6 | 7 | ## Time stamps from [YouTube video](https://www.youtube.com/watch?v=MhkGQAoc7bc) 8 | * 0:50 Babel overview 9 | * 1:29 Webpack config 10 | * 2:37 NPM install 11 | * 3:13 Looking at client.js & breaking down React 12 | * 5:45 Serving content from file 13 | * 6:18 Live reload w/ npm install -S webpack-dev-server 14 | * 7:10 webpack dev server --content-base src 15 | * 7:55 --Inline --hot (live reload) 16 | * 8:30 Creating a "dev" command in NPM 17 | 18 | -------------------------------------------------------------------------------- /4-redux/src/js/1-basic-setup.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "redux"; 2 | 3 | const reducer = (initialState=0, action) => { 4 | if (action.type === "INC") { 5 | return initialState + 1; 6 | } else if (action.type === "DEC") { 7 | return initialState - 1; 8 | } 9 | return initialState; 10 | } 11 | 12 | const store = createStore(reducer, 1) 13 | 14 | store.subscribe(() => { 15 | console.log("store changed", store.getState()); 16 | }) 17 | 18 | store.dispatch({type: "INC"}) 19 | store.dispatch({type: "INC"}) 20 | store.dispatch({type: "INC"}) 21 | store.dispatch({type: "DEC"}) 22 | store.dispatch({type: "DEC"}) 23 | store.dispatch({type: "DEC"}) 24 | -------------------------------------------------------------------------------- /3-flux/src/js/client.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { Router, Route, IndexRoute, hashHistory } from "react-router"; 4 | 5 | import Favorites from "./pages/Favorites"; 6 | import Todos from "./pages/Todos"; 7 | import Layout from "./pages/Layout"; 8 | import Settings from "./pages/Settings"; 9 | 10 | const app = document.getElementById('app'); 11 | 12 | ReactDOM.render( 13 | <Router history={hashHistory}> 14 | <Route path="/" component={Layout}> 15 | <IndexRoute component={Todos}></IndexRoute> 16 | <Route path="favorites" component={Favorites}></Route> 17 | <Route path="settings" component={Settings}></Route> 18 | </Route> 19 | </Router>, 20 | app); 21 | -------------------------------------------------------------------------------- /2-react-router/src/js/client.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { Router, Route, IndexRoute, hashHistory } from "react-router"; 4 | 5 | import Archives from "./pages/Archives"; 6 | import Featured from "./pages/Featured"; 7 | import Layout from "./pages/Layout"; 8 | import Settings from "./pages/Settings"; 9 | 10 | const app = document.getElementById('app'); 11 | 12 | ReactDOM.render( 13 | <Router history={hashHistory}> 14 | <Route path="/" component={Layout}> 15 | <IndexRoute component={Featured}></IndexRoute> 16 | <Route path="archives(/:article)" name="archives" component={Archives}></Route> 17 | <Route path="settings" name="settings" component={Settings}></Route> 18 | </Route> 19 | </Router>, 20 | app); 21 | -------------------------------------------------------------------------------- /3-flux/src/js/pages/Layout.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router"; 3 | 4 | import Footer from "../components/layout/Footer"; 5 | import Nav from "../components/layout/Nav"; 6 | 7 | export default class Layout extends React.Component { 8 | render() { 9 | const { location } = this.props; 10 | const containerStyle = { 11 | marginTop: "60px" 12 | }; 13 | 14 | return ( 15 | <div> 16 | 17 | <Nav location={location} /> 18 | 19 | <div class="container" style={containerStyle}> 20 | <div class="row"> 21 | <div class="col-lg-12"> 22 | 23 | {this.props.children} 24 | 25 | </div> 26 | </div> 27 | <Footer/> 28 | </div> 29 | </div> 30 | 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /2-react-router/src/js/pages/Layout.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router"; 3 | 4 | import Footer from "../components/layout/Footer"; 5 | import Nav from "../components/layout/Nav"; 6 | 7 | export default class Layout extends React.Component { 8 | render() { 9 | const { location } = this.props; 10 | const containerStyle = { 11 | marginTop: "60px" 12 | }; 13 | console.log("layout"); 14 | return ( 15 | <div> 16 | 17 | <Nav location={location} /> 18 | 19 | <div class="container" style={containerStyle}> 20 | <div class="row"> 21 | <div class="col-lg-12"> 22 | <h1>KillerNews.net</h1> 23 | 24 | {this.props.children} 25 | 26 | </div> 27 | </div> 28 | <Footer/> 29 | </div> 30 | </div> 31 | 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /6-mobx-react/src/js/TodoStore.js: -------------------------------------------------------------------------------- 1 | import { computed, observable } from "mobx" 2 | 3 | class Todo { 4 | @observable value 5 | @observable id 6 | @observable complete 7 | 8 | constructor(value) { 9 | this.value = value 10 | this.id = Date.now() 11 | this.complete = false 12 | } 13 | } 14 | 15 | export class TodoStore { 16 | @observable todos = [] 17 | @observable filter = "" 18 | @computed get filteredTodos() { 19 | var matchesFilter = new RegExp(this.filter, "i") 20 | return this.todos.filter(todo => !this.filter || matchesFilter.test(todo.value)) 21 | } 22 | 23 | createTodo(value) { 24 | this.todos.push(new Todo(value)) 25 | } 26 | 27 | clearComplete = () => { 28 | const incompleteTodos = this.todos.filter(todo => !todo.complete) 29 | this.todos.replace(incompleteTodos) 30 | } 31 | } 32 | 33 | export default new TodoStore 34 | 35 | -------------------------------------------------------------------------------- /3-flux/src/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en"> 3 | 4 | <head> 5 | <meta charset="utf-8"> 6 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 | <meta name="viewport" content="width=device-width, initial-scale=1"> 8 | <meta name="description" content=""> 9 | <meta name="author" content=""> 10 | <title>React 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /2-react-router/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | React 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /2-react-router/src/js/pages/Archives.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Article from "../components/Article"; 4 | 5 | export default class Archives extends React.Component { 6 | render() { 7 | const { query } = this.props.location; 8 | const { params } = this.props; 9 | const { article } = params; 10 | const { date, filter } = query; 11 | 12 | const Articles = [ 13 | "Some Article", 14 | "Some Other Article", 15 | "Yet Another Article", 16 | "Still More", 17 | "Fake Article", 18 | "Partial Article", 19 | "American Article", 20 | "Mexican Article", 21 | ].map((title, i) =>
); 22 | 23 | return ( 24 |
25 |

Archives

26 | article: {article}, date: {date}, filter: {filter} 27 |
{Articles}
28 |
29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /3-flux/src/js/actions/TodoActions.js: -------------------------------------------------------------------------------- 1 | import dispatcher from "../dispatcher"; 2 | 3 | export function createTodo(text) { 4 | dispatcher.dispatch({ 5 | type: "CREATE_TODO", 6 | text, 7 | }); 8 | } 9 | 10 | export function deleteTodo(id) { 11 | dispatcher.dispatch({ 12 | type: "DELETE_TODO", 13 | id, 14 | }); 15 | } 16 | 17 | export function reloadTodos() { 18 | // axios("http://someurl.com/somedataendpoint").then((data) => { 19 | // console.log("got the data!", data); 20 | // }) 21 | dispatcher.dispatch({type: "FETCH_TODOS"}); 22 | setTimeout(() => { 23 | dispatcher.dispatch({type: "RECEIVE_TODOS", todos: [ 24 | { 25 | id: 8484848484, 26 | text: "Go Shopping Again", 27 | complete: false 28 | }, 29 | { 30 | id: 6262627272, 31 | text: "Hug Wife", 32 | complete: true 33 | }, 34 | ]}); 35 | }, 1000); 36 | } 37 | -------------------------------------------------------------------------------- /6-mobx-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-mobx-todos", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --content-base src --inline --hot" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "mobx": "^2.3.7", 14 | "mobx-react": "^3.5.1", 15 | "react": "^15.2.1", 16 | "react-dom": "^15.3.0" 17 | }, 18 | "devDependencies": { 19 | "babel-core": "^6.17.0", 20 | "babel-loader": "^6.2.4", 21 | "babel-plugin-transform-class-properties": "^6.10.2", 22 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 23 | "babel-preset-es2015": "^6.9.0", 24 | "babel-preset-react": "^6.11.1", 25 | "css-loader": "^0.23.1", 26 | "react-addons-test-utils": "^15.3.0", 27 | "style-loader": "^0.13.1", 28 | "webpack": "^1.13.1", 29 | "webpack-dev-server": "^1.14.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /1-basic-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tutorials", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "dependencies": { 7 | "babel-core": "^6.17.0", 8 | "babel-loader": "^6.2.0", 9 | "babel-plugin-add-module-exports": "^0.1.2", 10 | "babel-plugin-react-html-attrs": "^2.0.0", 11 | "babel-plugin-transform-class-properties": "^6.3.13", 12 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 13 | "babel-preset-es2015": "^6.3.13", 14 | "babel-preset-react": "^6.3.13", 15 | "babel-preset-stage-0": "^6.3.13", 16 | "react": "^0.14.6", 17 | "react-dom": "^0.14.6", 18 | "webpack": "^1.12.9", 19 | "webpack-dev-server": "^1.14.1" 20 | }, 21 | "devDependencies": {}, 22 | "scripts": { 23 | "dev": "webpack-dev-server --content-base src --inline --hot", 24 | "test": "echo \"Error: no test specified\" && exit 1" 25 | }, 26 | "author": "", 27 | "license": "ISC" 28 | } 29 | -------------------------------------------------------------------------------- /2-react-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tutorials", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "dependencies": { 7 | "babel-core": "^6.17.0", 8 | "babel-loader": "^6.2.0", 9 | "babel-plugin-add-module-exports": "^0.1.2", 10 | "babel-plugin-react-html-attrs": "^2.0.0", 11 | "babel-plugin-transform-class-properties": "^6.3.13", 12 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 13 | "babel-preset-es2015": "^6.3.13", 14 | "babel-preset-react": "^6.3.13", 15 | "babel-preset-stage-0": "^6.3.13", 16 | "history": "^1.17.0", 17 | "react": "^0.14.6", 18 | "react-dom": "^0.14.6", 19 | "react-router": "^1.0.3", 20 | "webpack": "^1.12.9", 21 | "webpack-dev-server": "^1.14.1" 22 | }, 23 | "devDependencies": {}, 24 | "scripts": { 25 | "dev": "webpack-dev-server --content-base src --inline --hot" 26 | }, 27 | "author": "", 28 | "license": "ISC" 29 | } 30 | -------------------------------------------------------------------------------- /3-flux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tutorials", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "dependencies": { 7 | "babel-core": "^6.18.2", 8 | "babel-loader": "^6.2.0", 9 | "babel-plugin-add-module-exports": "^0.1.2", 10 | "babel-plugin-react-html-attrs": "^2.0.0", 11 | "babel-plugin-transform-class-properties": "^6.3.13", 12 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 13 | "babel-preset-es2015": "^6.3.13", 14 | "babel-preset-react": "^6.3.13", 15 | "babel-preset-stage-0": "^6.3.13", 16 | "flux": "^2.1.1", 17 | "history": "^1.17.0", 18 | "react": "^0.14.6", 19 | "react-dom": "^0.14.6", 20 | "react-router": "^1.0.3", 21 | "webpack": "^1.12.9", 22 | "webpack-dev-server": "^1.14.1" 23 | }, 24 | "devDependencies": {}, 25 | "scripts": { 26 | "dev": "webpack-dev-server --content-base src --inline --hot" 27 | }, 28 | "author": "", 29 | "license": "ISC" 30 | } 31 | -------------------------------------------------------------------------------- /3-flux/webpack.config.js: -------------------------------------------------------------------------------- 1 | var debug = process.env.NODE_ENV !== "production"; 2 | var webpack = require('webpack'); 3 | var path = require('path'); 4 | 5 | module.exports = { 6 | context: path.join(__dirname, "src"), 7 | devtool: debug ? "inline-sourcemap" : null, 8 | entry: "./js/client.js", 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.jsx?$/, 13 | exclude: /(node_modules|bower_components)/, 14 | loader: 'babel-loader', 15 | query: { 16 | presets: ['react', 'es2015', 'stage-0'], 17 | plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'], 18 | } 19 | } 20 | ] 21 | }, 22 | output: { 23 | path: __dirname + "/src/", 24 | filename: "client.min.js" 25 | }, 26 | plugins: debug ? [] : [ 27 | new webpack.optimize.DedupePlugin(), 28 | new webpack.optimize.OccurenceOrderPlugin(), 29 | new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /4-redux/webpack.config.js: -------------------------------------------------------------------------------- 1 | var debug = process.env.NODE_ENV !== "production"; 2 | var webpack = require('webpack'); 3 | var path = require('path'); 4 | 5 | module.exports = { 6 | context: path.join(__dirname, "src"), 7 | devtool: debug ? "inline-sourcemap" : null, 8 | entry: "./js/client.js", 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.jsx?$/, 13 | exclude: /(node_modules|bower_components)/, 14 | loader: 'babel-loader', 15 | query: { 16 | presets: ['react', 'es2015', 'stage-0'], 17 | plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'], 18 | } 19 | } 20 | ] 21 | }, 22 | output: { 23 | path: __dirname + "/src/", 24 | filename: "client.min.js" 25 | }, 26 | plugins: debug ? [] : [ 27 | new webpack.optimize.DedupePlugin(), 28 | new webpack.optimize.OccurenceOrderPlugin(), 29 | new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /6-mobx-react/webpack.config.js: -------------------------------------------------------------------------------- 1 | var debug = process.env.NODE_ENV !== "production"; 2 | var webpack = require('webpack'); 3 | var path = require('path'); 4 | 5 | module.exports = { 6 | context: path.join(__dirname, "src"), 7 | devtool: debug ? "inline-sourcemap" : null, 8 | entry: "./js/main.js", 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.js$/, 13 | exclude: /(node_modules|bower_components)/, 14 | loader: 'babel-loader', 15 | query: { presets: ['es2015', 'react'], plugins: ["transform-decorators-legacy", "transform-class-properties"] } 16 | }, 17 | { test: /\.css$/, loader: "style-loader!css-loader" }, 18 | ] 19 | }, 20 | output: { 21 | path: path.join(__dirname, "src"), 22 | filename: "main.min.js" 23 | }, 24 | plugins: debug ? [] : [ 25 | new webpack.optimize.DedupePlugin(), 26 | new webpack.optimize.OccurenceOrderPlugin(), 27 | new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), 28 | ], 29 | }; 30 | -------------------------------------------------------------------------------- /1-basic-react/webpack.config.js: -------------------------------------------------------------------------------- 1 | var debug = process.env.NODE_ENV !== "production"; 2 | var webpack = require('webpack'); 3 | var path = require('path'); 4 | 5 | module.exports = { 6 | context: path.join(__dirname, "src"), 7 | devtool: debug ? "inline-sourcemap" : false, 8 | entry: "./js/client.js", 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.jsx?$/, 13 | exclude: /(node_modules|bower_components)/, 14 | loader: 'babel-loader', 15 | query: { 16 | presets: ['react', 'es2015', 'stage-0'], 17 | plugins: ['react-html-attrs', 'transform-decorators-legacy', 'transform-class-properties'], 18 | } 19 | } 20 | ] 21 | }, 22 | output: { 23 | path: __dirname + "/src/", 24 | filename: "client.min.js" 25 | }, 26 | plugins: debug ? [] : [ 27 | new webpack.optimize.DedupePlugin(), 28 | new webpack.optimize.OccurrenceOrderPlugin(), 29 | new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /2-react-router/webpack.config.js: -------------------------------------------------------------------------------- 1 | var debug = process.env.NODE_ENV !== "production"; 2 | var webpack = require('webpack'); 3 | var path = require('path'); 4 | 5 | module.exports = { 6 | context: path.join(__dirname, "src"), 7 | devtool: debug ? "inline-sourcemap" : null, 8 | entry: "./js/client.js", 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.jsx?$/, 13 | exclude: /(node_modules|bower_components)/, 14 | loader: 'babel-loader', 15 | query: { 16 | presets: ['react', 'es2015', 'stage-0'], 17 | plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'], 18 | } 19 | } 20 | ] 21 | }, 22 | output: { 23 | path: __dirname + "/src/", 24 | filename: "client.min.js" 25 | }, 26 | plugins: debug ? [] : [ 27 | new webpack.optimize.DedupePlugin(), 28 | new webpack.optimize.OccurenceOrderPlugin(), 29 | new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /5-redux-react/webpack.config.js: -------------------------------------------------------------------------------- 1 | var debug = process.env.NODE_ENV !== "production"; 2 | var webpack = require('webpack'); 3 | var path = require('path'); 4 | 5 | module.exports = { 6 | context: path.join(__dirname, "src"), 7 | devtool: debug ? "inline-sourcemap" : null, 8 | entry: "./js/client.js", 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.jsx?$/, 13 | exclude: /(node_modules|bower_components)/, 14 | loader: 'babel-loader', 15 | query: { 16 | presets: ['react', 'es2015', 'stage-0'], 17 | plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'], 18 | } 19 | } 20 | ] 21 | }, 22 | output: { 23 | path: __dirname + "/src/", 24 | filename: "client.min.js" 25 | }, 26 | plugins: debug ? [] : [ 27 | new webpack.optimize.DedupePlugin(), 28 | new webpack.optimize.OccurenceOrderPlugin(), 29 | new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /5-redux-react/src/js/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { connect } from "react-redux" 3 | 4 | import { fetchUser } from "../actions/userActions" 5 | import { fetchTweets } from "../actions/tweetsActions" 6 | 7 | @connect((store) => { 8 | return { 9 | user: store.user.user, 10 | userFetched: store.user.fetched, 11 | tweets: store.tweets.tweets, 12 | }; 13 | }) 14 | export default class Layout extends React.Component { 15 | componentWillMount() { 16 | this.props.dispatch(fetchUser()) 17 | } 18 | 19 | fetchTweets() { 20 | this.props.dispatch(fetchTweets()) 21 | } 22 | 23 | render() { 24 | const { user, tweets } = this.props; 25 | 26 | if (!tweets.length) { 27 | return 28 | } 29 | 30 | const mappedTweets = tweets.map(tweet =>
  • {tweet.text}
  • ) 31 | 32 | return
    33 |

    {user.name}

    34 |
      {mappedTweets}
    35 |
    36 | } 37 | } 38 | -------------------------------------------------------------------------------- /6-mobx-react/src/css/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | body { 8 | font-family: 'Slabo 27px', serif; 9 | background: #f5f5f5; 10 | color: #4d4d4d; 11 | min-width: 230px; 12 | max-width: 550px; 13 | margin: 0 auto; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-font-smoothing: antialiased; 16 | font-smoothing: antialiased; 17 | font-weight: 300; 18 | } 19 | 20 | input { 21 | border-radius: 5px; 22 | padding: 5px; 23 | border: 1px solid rgba(0,0,0,0.3); 24 | margin-right: 10px 25 | } 26 | 27 | input::-webkit-input-placeholder { 28 | font-style: italic; 29 | font-weight: 300; 30 | color: rgba(0,0,0,0.3); 31 | } 32 | 33 | input::-moz-placeholder { 34 | font-style: italic; 35 | font-weight: 300; 36 | color: rgba(0,0,0,0.3); 37 | } 38 | 39 | input::input-placeholder { 40 | font-style: italic; 41 | font-weight: 300; 42 | color: rgba(0,0,0,0.3); 43 | } 44 | 45 | h1 { 46 | font-weight: 100; 47 | font-size: 100px; 48 | padding:0; 49 | margin: 0; 50 | } 51 | -------------------------------------------------------------------------------- /5-redux-react/src/js/reducers/userReducer.js: -------------------------------------------------------------------------------- 1 | export default function reducer(state={ 2 | user: { 3 | id: null, 4 | name: null, 5 | age: null, 6 | }, 7 | fetching: false, 8 | fetched: false, 9 | error: null, 10 | }, action) { 11 | 12 | switch (action.type) { 13 | case "FETCH_USER": { 14 | return {...state, fetching: true} 15 | } 16 | case "FETCH_USER_REJECTED": { 17 | return {...state, fetching: false, error: action.payload} 18 | } 19 | case "FETCH_USER_FULFILLED": { 20 | return { 21 | ...state, 22 | fetching: false, 23 | fetched: true, 24 | user: action.payload, 25 | } 26 | } 27 | case "SET_USER_NAME": { 28 | return { 29 | ...state, 30 | user: {...state.user, name: action.payload}, 31 | } 32 | } 33 | case "SET_USER_AGE": { 34 | return { 35 | ...state, 36 | user: {...state.user, age: action.payload}, 37 | } 38 | } 39 | } 40 | 41 | return state 42 | } 43 | -------------------------------------------------------------------------------- /4-redux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tutorials", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "dependencies": { 7 | "axios": "^0.12.0", 8 | "babel-core": "^6.17.0", 9 | "babel-loader": "^6.2.0", 10 | "babel-plugin-add-module-exports": "^0.1.2", 11 | "babel-plugin-react-html-attrs": "^2.0.0", 12 | "babel-plugin-transform-class-properties": "^6.3.13", 13 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 14 | "babel-preset-es2015": "^6.3.13", 15 | "babel-preset-react": "^6.3.13", 16 | "babel-preset-stage-0": "^6.3.13", 17 | "react": "^0.14.6", 18 | "react-dom": "^0.14.6", 19 | "redux": "^3.5.2", 20 | "redux-logger": "^2.6.1", 21 | "redux-promise-middleware": "^3.2.0", 22 | "redux-thunk": "^2.1.0", 23 | "webpack": "^1.12.9", 24 | "webpack-dev-server": "^1.14.1" 25 | }, 26 | "devDependencies": {}, 27 | "scripts": { 28 | "dev": "./node_modules/.bin/webpack-dev-server --content-base src --inline --hot", 29 | "test": "echo \"Error: no test specified\" && exit 1" 30 | }, 31 | "author": "", 32 | "license": "ISC" 33 | } 34 | -------------------------------------------------------------------------------- /5-redux-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tutorials", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "dependencies": { 7 | "axios": "^0.12.0", 8 | "babel-core": "^6.18.2", 9 | "babel-loader": "^6.2.0", 10 | "babel-plugin-add-module-exports": "^0.1.2", 11 | "babel-plugin-react-html-attrs": "^2.0.0", 12 | "babel-plugin-transform-class-properties": "^6.3.13", 13 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 14 | "babel-preset-es2015": "^6.3.13", 15 | "babel-preset-react": "^6.3.13", 16 | "babel-preset-stage-0": "^6.3.13", 17 | "react": "^0.14.6", 18 | "react-dom": "^0.14.6", 19 | "react-redux": "^4.4.5", 20 | "redux": "^3.5.2", 21 | "redux-logger": "^2.6.1", 22 | "redux-promise-middleware": "^3.2.0", 23 | "redux-thunk": "^2.1.0", 24 | "webpack": "^1.12.9", 25 | "webpack-dev-server": "^1.14.1" 26 | }, 27 | "devDependencies": {}, 28 | "scripts": { 29 | "dev": "./node_modules/.bin/webpack-dev-server --content-base src --inline --hot", 30 | "test": "echo \"Error: no test specified\" && exit 1" 31 | }, 32 | "author": "", 33 | "license": "ISC" 34 | } 35 | -------------------------------------------------------------------------------- /4-redux/src/js/client.js: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, createStore } from "redux"; 2 | import axios from "axios"; 3 | import logger from "redux-logger"; 4 | import thunk from "redux-thunk"; 5 | import promise from "redux-promise-middleware"; 6 | 7 | const initialState = { 8 | fetching: false, 9 | fetched: false, 10 | users: [], 11 | error: null, 12 | }; 13 | 14 | const reducer = (state=initialState, action) => { 15 | switch (action.type) { 16 | case "FETCH_USERS_PENDING": { 17 | return {...state, fetching: true} 18 | break; 19 | } 20 | case "FETCH_USERS_REJECTED": { 21 | return {...state, fetching: false, error: action.payload} 22 | break; 23 | } 24 | case "FETCH_USERS_FULFILLED": { 25 | return { 26 | ...state, 27 | fetching: false, 28 | fetched: true, 29 | users: action.payload, 30 | } 31 | break; 32 | } 33 | } 34 | return state 35 | } 36 | 37 | const middleware = applyMiddleware(promise(), thunk, logger()) 38 | const store = createStore(reducer, middleware) 39 | 40 | store.dispatch({ 41 | type: "FETCH_USERS", 42 | payload: axios.get("http://rest.learncode.academy/api/wstern/users") 43 | }) 44 | -------------------------------------------------------------------------------- /4-redux/src/js/4-async-middleware.js: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, createStore } from "redux"; 2 | import axios from "axios"; 3 | import logger from "redux-logger"; 4 | import thunk from "redux-thunk"; 5 | import promise from "redux-promise-middleware"; 6 | 7 | const initialState = { 8 | fetching: false, 9 | fetched: false, 10 | users: [], 11 | error: null, 12 | }; 13 | 14 | const reducer = (state=initialState, action) => { 15 | switch (action.type) { 16 | case "FETCH_USERS_PENDING": { 17 | return {...state, fetching: true} 18 | break; 19 | } 20 | case "FETCH_USERS_REJECTED": { 21 | return {...state, fetching: false, error: action.payload} 22 | break; 23 | } 24 | case "FETCH_USERS_FULFILLED": { 25 | return { 26 | ...state, 27 | fetching: false, 28 | fetched: true, 29 | users: action.payload, 30 | } 31 | break; 32 | } 33 | } 34 | return state 35 | } 36 | 37 | const middleware = applyMiddleware(promise(), thunk, logger()) 38 | const store = createStore(reducer, middleware) 39 | 40 | store.dispatch({ 41 | type: "FETCH_USERS", 42 | payload: axios.get("http://rest.learncode.academy/api/wstern/users") 43 | }) 44 | -------------------------------------------------------------------------------- /6-mobx-react/src/js/TodoList.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { observer } from "mobx-react" 3 | 4 | 5 | @observer 6 | export default class TodoList extends React.Component { 7 | createNew(e) { 8 | if (e.which === 13) { 9 | this.props.store.createTodo(e.target.value) 10 | e.target.value = "" 11 | } 12 | } 13 | 14 | filter(e) { 15 | this.props.store.filter = e.target.value 16 | } 17 | 18 | toggleComplete(todo) { 19 | todo.complete = !todo.complete 20 | } 21 | 22 | render() { 23 | const { clearComplete, filter, filteredTodos, todos } = this.props.store 24 | 25 | const todoLis = filteredTodos.map(todo => ( 26 |
  • 27 | 28 | {todo.value} 29 |
  • 30 | )) 31 | return
    32 |

    todos

    33 | 34 | 35 |
      {todoLis}
    36 | Clear Complete 37 |
    38 | } 39 | } 40 | -------------------------------------------------------------------------------- /4-redux/src/js/3-middleware.js: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, createStore } from "redux"; 2 | 3 | const reducer = (initialState=0, action) => { 4 | if (action.type === "INC") { 5 | return initialState + 1; 6 | } else if (action.type === "DEC") { 7 | return initialState - 1; 8 | } else if (action.type === "MULT") { 9 | throw new Error("AHHHH!!"); 10 | } 11 | return initialState; 12 | } 13 | 14 | const logger = (store) => (next) => (action) => { 15 | console.log("Logged", action); 16 | return next(action); 17 | }; 18 | 19 | 20 | const errorHandler = (store) => (next) => (action) => { 21 | try { 22 | return next(action); 23 | } catch(e) { 24 | console.log("ERROR!", e); 25 | } 26 | }; 27 | 28 | const middleware = applyMiddleware( 29 | logger, 30 | errorHandler 31 | ) 32 | const store = createStore(reducer, middleware) 33 | 34 | store.subscribe(() => { 35 | console.log("store changed", store.getState()); 36 | }) 37 | 38 | store.dispatch({type: "INC"}) 39 | store.dispatch({type: "INC"}) 40 | store.dispatch({type: "INC"}) 41 | store.dispatch({type: "DEC"}) 42 | store.dispatch({type: "DEC"}) 43 | store.dispatch({type: "DEC"}) 44 | store.dispatch({type: "MULT"}) 45 | store.dispatch({type: "DEC"}) 46 | -------------------------------------------------------------------------------- /3-flux/src/js/pages/Todos.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Todo from "../components/Todo"; 4 | import * as TodoActions from "../actions/TodoActions"; 5 | import TodoStore from "../stores/TodoStore"; 6 | 7 | 8 | export default class Todos extends React.Component { 9 | constructor() { 10 | super(); 11 | this.getTodos = this.getTodos.bind(this); 12 | this.state = { 13 | todos: TodoStore.getAll(), 14 | }; 15 | } 16 | 17 | componentWillMount() { 18 | TodoStore.on("change", this.getTodos); 19 | } 20 | 21 | componentWillUnmount() { 22 | TodoStore.removeListener("change", this.getTodos); 23 | } 24 | 25 | getTodos() { 26 | this.setState({ 27 | todos: TodoStore.getAll(), 28 | }); 29 | } 30 | 31 | reloadTodos() { 32 | TodoActions.reloadTodos(); 33 | } 34 | 35 | render() { 36 | const { todos } = this.state; 37 | 38 | const TodoComponents = todos.map((todo) => { 39 | return ; 40 | }); 41 | 42 | return ( 43 |
    44 | 45 |

    Todos

    46 |
      {TodoComponents}
    47 |
    48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /3-flux/src/js/stores/TodoStore.js: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "events"; 2 | 3 | import dispatcher from "../dispatcher"; 4 | 5 | class TodoStore extends EventEmitter { 6 | constructor() { 7 | super() 8 | this.todos = [ 9 | { 10 | id: 113464613, 11 | text: "Go Shopping", 12 | complete: false 13 | }, 14 | { 15 | id: 235684679, 16 | text: "Pay Water Bill", 17 | complete: false 18 | }, 19 | ]; 20 | } 21 | 22 | createTodo(text) { 23 | const id = Date.now(); 24 | 25 | this.todos.push({ 26 | id, 27 | text, 28 | complete: false, 29 | }); 30 | 31 | this.emit("change"); 32 | } 33 | 34 | getAll() { 35 | return this.todos; 36 | } 37 | 38 | handleActions(action) { 39 | switch(action.type) { 40 | case "CREATE_TODO": { 41 | this.createTodo(action.text); 42 | break; 43 | } 44 | case "RECEIVE_TODOS": { 45 | this.todos = action.todos; 46 | this.emit("change"); 47 | break; 48 | } 49 | } 50 | } 51 | 52 | } 53 | 54 | const todoStore = new TodoStore; 55 | dispatcher.register(todoStore.handleActions.bind(todoStore)); 56 | 57 | export default todoStore; 58 | -------------------------------------------------------------------------------- /2-react-router/src/js/pages/Featured.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Article from "../components/Article"; 4 | 5 | export default class Featured extends React.Component { 6 | render() { 7 | const Articles = [ 8 | "Some Article", 9 | "Some Other Article", 10 | "Yet Another Article", 11 | "Still More", 12 | "Some Article", 13 | "Some Other Article", 14 | "Yet Another Article", 15 | "Still More", 16 | "Some Article", 17 | "Some Other Article", 18 | "Yet Another Article", 19 | "Still More", 20 | ].map((title, i) =>
    ); 21 | 22 | const adText = [ 23 | "Ad spot #1", 24 | "Ad spot #2", 25 | "Ad spot #3", 26 | "Ad spot #4", 27 | "Ad spot #5", 28 | ]; 29 | 30 | const randomAd = adText[Math.round( Math.random() * (adText.length-1) )]; 31 | console.log("featured"); 32 | return ( 33 |
    34 |
    35 |
    36 |
    37 | {randomAd} 38 |
    39 |
    40 |
    41 | 42 |
    {Articles}
    43 |
    44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /5-redux-react/src/js/actions/tweetsActions.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export function fetchTweets() { 4 | return function(dispatch) { 5 | dispatch({type: "FETCH_TWEETS"}); 6 | 7 | /* 8 | http://rest.learncode.academy is a public test server, so another user's experimentation can break your tests 9 | If you get console errors due to bad data: 10 | - change "reacttest" below to any other username 11 | - post some tweets to http://rest.learncode.academy/api/yourusername/tweets 12 | */ 13 | axios.get("http://rest.learncode.academy/api/reacttest/tweets") 14 | .then((response) => { 15 | dispatch({type: "FETCH_TWEETS_FULFILLED", payload: response.data}) 16 | }) 17 | .catch((err) => { 18 | dispatch({type: "FETCH_TWEETS_REJECTED", payload: err}) 19 | }) 20 | } 21 | } 22 | 23 | export function addTweet(id, text) { 24 | return { 25 | type: 'ADD_TWEET', 26 | payload: { 27 | id, 28 | text, 29 | }, 30 | } 31 | } 32 | 33 | export function updateTweet(id, text) { 34 | return { 35 | type: 'UPDATE_TWEET', 36 | payload: { 37 | id, 38 | text, 39 | }, 40 | } 41 | } 42 | 43 | export function deleteTweet(id) { 44 | return { type: 'DELETE_TWEET', payload: id} 45 | } 46 | -------------------------------------------------------------------------------- /4-redux/src/js/2-multiple-reducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers, createStore } from "redux"; 2 | 3 | // I would live in a separate file 4 | const userReducer = (state={}, action) => { 5 | switch(action.type) { 6 | case "SET_NAME": { 7 | return {...state, name: action.payload}; 8 | break; 9 | } 10 | case "SET_AGE": { 11 | return {...state, age: action.payload}; 12 | break; 13 | } 14 | } 15 | return state; 16 | } 17 | 18 | // I would live in a separate file 19 | const tweetsReducer = (state=[], action) => { 20 | switch(action.type) { 21 | case "ADD_TWEET": { 22 | return state.concat({ 23 | id: Date.now(), //fake an ID by using a timestamp 24 | text: action.payload, 25 | }); 26 | break; 27 | } 28 | } 29 | return state; 30 | } 31 | 32 | const reducers = combineReducers({ 33 | user: userReducer, 34 | tweets: tweetsReducer 35 | }) 36 | 37 | const store = createStore(reducers) 38 | 39 | store.subscribe(() => { 40 | console.log("store changed", store.getState()); 41 | }) 42 | 43 | store.dispatch({type: "SET_NAME", payload: "Will"}) 44 | store.dispatch({type: "SET_AGE", payload: 35}) 45 | store.dispatch({type: "SET_AGE", payload: 34}) 46 | store.dispatch({type: "ADD_TWEET", payload: "OMG LIKE LOL"}) 47 | store.dispatch({type: "ADD_TWEET", payload: "I am so like seriously like totally like right now"}) 48 | -------------------------------------------------------------------------------- /5-redux-react/src/js/reducers/tweetsReducer.js: -------------------------------------------------------------------------------- 1 | export default function reducer(state={ 2 | tweets: [], 3 | fetching: false, 4 | fetched: false, 5 | error: null, 6 | }, action) { 7 | 8 | switch (action.type) { 9 | case "FETCH_TWEETS": { 10 | return {...state, fetching: true} 11 | } 12 | case "FETCH_TWEETS_REJECTED": { 13 | return {...state, fetching: false, error: action.payload} 14 | } 15 | case "FETCH_TWEETS_FULFILLED": { 16 | return { 17 | ...state, 18 | fetching: false, 19 | fetched: true, 20 | tweets: action.payload, 21 | } 22 | } 23 | case "ADD_TWEET": { 24 | return { 25 | ...state, 26 | tweets: [...state.tweets, action.payload], 27 | } 28 | } 29 | case "UPDATE_TWEET": { 30 | const { id, text } = action.payload 31 | const newTweets = [...state.tweets] 32 | const tweetToUpdate = newTweets.findIndex(tweet => tweet.id === id) 33 | newTweets[tweetToUpdate] = action.payload; 34 | 35 | return { 36 | ...state, 37 | tweets: newTweets, 38 | } 39 | } 40 | case "DELETE_TWEET": { 41 | return { 42 | ...state, 43 | tweets: state.tweets.filter(tweet => tweet.id !== action.payload), 44 | } 45 | } 46 | } 47 | 48 | return state 49 | } 50 | -------------------------------------------------------------------------------- /3-flux/src/js/components/layout/Nav.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { IndexLink, Link } from "react-router"; 3 | 4 | export default class Nav extends React.Component { 5 | constructor() { 6 | super() 7 | this.state = { 8 | collapsed: true, 9 | }; 10 | } 11 | 12 | toggleCollapse() { 13 | const collapsed = !this.state.collapsed; 14 | this.setState({collapsed}); 15 | } 16 | 17 | render() { 18 | const { location } = this.props; 19 | const { collapsed } = this.state; 20 | const featuredClass = location.pathname === "/" ? "active" : ""; 21 | const archivesClass = location.pathname.match(/^\/favorites/) ? "active" : ""; 22 | const settingsClass = location.pathname.match(/^\/settings/) ? "active" : ""; 23 | const navClass = collapsed ? "collapse" : ""; 24 | 25 | return ( 26 | 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /2-react-router/src/js/components/layout/Nav.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { IndexLink, Link } from "react-router"; 3 | 4 | export default class Nav extends React.Component { 5 | constructor() { 6 | super() 7 | this.state = { 8 | collapsed: true, 9 | }; 10 | } 11 | 12 | toggleCollapse() { 13 | const collapsed = !this.state.collapsed; 14 | this.setState({collapsed}); 15 | } 16 | 17 | render() { 18 | const { location } = this.props; 19 | const { collapsed } = this.state; 20 | const featuredClass = location.pathname === "/" ? "active" : ""; 21 | const archivesClass = location.pathname.match(/^\/archives/) ? "active" : ""; 22 | const settingsClass = location.pathname.match(/^\/settings/) ? "active" : ""; 23 | const navClass = collapsed ? "collapse" : ""; 24 | 25 | return ( 26 | 51 | ); 52 | } 53 | } 54 | --------------------------------------------------------------------------------