├── .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 |
16 |
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 |
14 |
15 |
16 |
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 |
21 |
22 |
23 |
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 |
21 |
22 |
23 |
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 |
16 |
17 |
18 | );
19 | }
20 |
21 | return (
22 |
23 | {text}
24 | {icon}
25 |
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 |
9 |
{title}
10 |
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.
11 |
More Info
12 |
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 |
14 |
15 |
16 |
17 |
18 |
19 | ,
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 |
14 |
15 |
16 |
17 |
18 |
19 | ,
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 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {this.props.children}
24 |
25 |
26 |
27 |
28 |
29 |
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 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
KillerNews.net
23 |
24 | {this.props.children}
25 |
26 |
27 |
28 |
29 |
30 |
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 |
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/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 load tweets
28 | }
29 |
30 | const mappedTweets = tweets.map(tweet => {tweet.text} )
31 |
32 | return
33 |
{user.name}
34 |
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
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 |
Reload!
45 |
Todos
46 |
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 |
27 |
28 |
36 |
37 |
38 |
39 | Todos
40 |
41 |
42 | Favorites
43 |
44 |
45 | Settings
46 |
47 |
48 |
49 |
50 |
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 |
27 |
28 |
36 |
37 |
38 |
39 | Featured
40 |
41 |
42 | Archives
43 |
44 |
45 | Settings
46 |
47 |
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------