├── .gitignore ├── 1. Redux & plain Javascript ├── v01-normal Javascript.html ├── v02-STORE,STATE,DISPATCH(ACTION),REDUCER.html ├── v03-exercise 01-apply for IncrementAsync Button.html ├── v04-exercise 02-sum of A and B.html ├── v05-solution 02-sum of A and B.html ├── v06-exercise03-structure for a bigger project │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ └── reducers │ │ └── index.js ├── v07-solution03-structure for a bigger project │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ └── reducers │ │ ├── counter.js │ │ ├── index.js │ │ └── sum.js ├── v08-middleware │ ├── _fakeServerApi │ │ └── index.js │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ │ └── index.js │ └── reducers │ │ ├── counter.js │ │ ├── index.js │ │ └── sum.js ├── v09-thunk middleware-exercise │ ├── _fakeServerApi │ │ └── index.js │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ │ └── index.js │ └── reducers │ │ ├── counter.js │ │ ├── index.js │ │ └── sum.js ├── v10-solution.docx └── v10-thunk middleware-solution │ ├── _fakeServerApi │ └── index.js │ ├── actions │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ └── index.js │ └── reducers │ ├── counter.js │ ├── images.js │ ├── index.js │ └── sum.js ├── 2. Redux & jquery ├── v01. convert to Jquery - exercise │ ├── _fakeServerApi │ │ └── index.js │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ │ └── index.js │ └── reducers │ │ ├── counter.js │ │ ├── images.js │ │ ├── index.js │ │ └── sum.js └── v02. convert to Jquery - solution │ ├── _fakeServerApi │ └── index.js │ ├── actions │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ └── index.js │ └── reducers │ ├── counter.js │ ├── images.js │ ├── index.js │ └── sum.js ├── 3. Redux & ES6 ├── v01. Arrow function - exercise │ ├── _fakeServerApi │ │ └── index.js │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ │ └── index.js │ └── reducers │ │ ├── counter.js │ │ ├── images.js │ │ ├── index.js │ │ └── sum.js ├── v02. Arrow function - solution │ ├── _fakeServerApi │ │ └── index.js │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ │ └── index.js │ └── reducers │ │ ├── counter.js │ │ ├── images.js │ │ ├── index.js │ │ └── sum.js ├── v03. const, let examples │ ├── 01let.html │ ├── 02let.html │ └── 03const.html ├── v04. default parameter, Object.assign() │ └── index.html ├── v05. ES6 - exercise │ ├── _fakeServerApi │ │ └── index.js │ ├── actions │ │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ │ └── index.js │ └── reducers │ │ ├── counter.js │ │ ├── images.js │ │ ├── index.js │ │ └── sum.js └── v06. ES6 - solution │ ├── _fakeServerApi │ └── index.js │ ├── actions │ └── index.js │ ├── index.html │ ├── index.js │ ├── middlewares │ └── index.js │ └── reducers │ ├── counter.js │ ├── images.js │ ├── index.js │ └── sum.js ├── 4. Redux & React ├── 1. only React │ ├── v01. simplest │ │ ├── .babelrc │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── server.js │ │ └── webpack.config.js │ ├── v02. State; React DevTools │ │ ├── .babelrc │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── server.js │ │ └── webpack.config.js │ ├── v03. child Component │ │ ├── .babelrc │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── server.js │ │ └── webpack.config.js │ ├── v04. ES6 - import, export, export default │ │ ├── .babelrc │ │ ├── components │ │ │ ├── Counter.js │ │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── server.js │ │ └── webpack.config.js │ ├── v05. props │ │ ├── .babelrc │ │ ├── components │ │ │ ├── Counter.js │ │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── server.js │ │ └── webpack.config.js │ └── v06. Stateless function & Key of list item │ │ ├── .babelrc │ │ ├── components │ │ ├── Counter.js │ │ ├── RandomImages.js │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── server.js │ │ └── webpack.config.js ├── 2. React & Redux │ ├── v01. step1 - insert Redux │ │ ├── .babelrc │ │ ├── components │ │ │ ├── Counter.js │ │ │ ├── Examples.js │ │ │ ├── RandomImages.js │ │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── redux │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── middlewares │ │ │ │ └── index.js │ │ │ ├── reducers │ │ │ │ ├── counter.js │ │ │ │ ├── images.js │ │ │ │ ├── index.js │ │ │ │ └── sum.js │ │ │ └── store │ │ │ │ └── config.js │ │ ├── server.js │ │ └── webpack.config.js │ ├── v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools │ │ ├── .babelrc │ │ ├── components │ │ │ ├── Counter.js │ │ │ ├── Examples.js │ │ │ ├── RandomImages.js │ │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── redux │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── middlewares │ │ │ │ └── index.js │ │ │ ├── reducers │ │ │ │ ├── counter.js │ │ │ │ ├── images.js │ │ │ │ ├── index.js │ │ │ │ └── sum.js │ │ │ └── store │ │ │ │ └── config.js │ │ ├── server.js │ │ └── webpack.config.js │ ├── v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator │ │ ├── .babelrc │ │ ├── components │ │ │ ├── Counter.js │ │ │ ├── Examples.js │ │ │ ├── RandomImages.js │ │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── redux │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── middlewares │ │ │ │ └── index.js │ │ │ ├── reducers │ │ │ │ ├── counter.js │ │ │ │ ├── images.js │ │ │ │ ├── index.js │ │ │ │ └── sum.js │ │ │ └── store │ │ │ │ └── config.js │ │ ├── server.js │ │ └── webpack.config.js │ ├── v04. react-redux -- Provider │ │ ├── .babelrc │ │ ├── components │ │ │ ├── Counter.js │ │ │ ├── Examples.js │ │ │ ├── RandomImages.js │ │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── redux │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── middlewares │ │ │ │ └── index.js │ │ │ ├── reducers │ │ │ │ ├── counter.js │ │ │ │ ├── images.js │ │ │ │ ├── index.js │ │ │ │ └── sum.js │ │ │ └── store │ │ │ │ └── config.js │ │ ├── server.js │ │ └── webpack.config.js │ ├── v05. react-redux -- Provider (shorter) │ │ ├── .babelrc │ │ ├── components │ │ │ ├── Counter.js │ │ │ ├── Examples.js │ │ │ ├── RandomImages.js │ │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── redux │ │ │ ├── actions │ │ │ │ └── index.js │ │ │ ├── middlewares │ │ │ │ └── index.js │ │ │ ├── reducers │ │ │ │ ├── counter.js │ │ │ │ ├── images.js │ │ │ │ ├── index.js │ │ │ │ └── sum.js │ │ │ └── store │ │ │ │ └── config.js │ │ ├── server.js │ │ └── webpack.config.js │ └── v06. react-redux -- Container, combineReducers, middlewares (thunk, logger) │ │ ├── .babelrc │ │ ├── components │ │ ├── Counter.js │ │ ├── Examples.js │ │ ├── RandomImages.js │ │ └── Sum.js │ │ ├── containers │ │ ├── Counter.js │ │ ├── RandomImages.js │ │ └── Sum.js │ │ ├── index.html │ │ ├── index.js │ │ ├── package.json │ │ ├── redux │ │ ├── actions │ │ │ └── index.js │ │ ├── middlewares │ │ │ └── index.js │ │ ├── reducers │ │ │ ├── counter.js │ │ │ ├── images.js │ │ │ ├── index.js │ │ │ └── sum.js │ │ └── store │ │ │ └── config.js │ │ ├── server.js │ │ └── webpack.config.js └── 3. React-router │ ├── .babelrc │ ├── components │ ├── App.js │ ├── Counter.js │ ├── Examples.js │ ├── Examples02.js │ ├── RandomImages.js │ └── Sum.js │ ├── containers │ ├── Counter.js │ ├── RandomImages.js │ └── Sum.js │ ├── index.html │ ├── index.js │ ├── package.json │ ├── redux │ ├── actions │ │ └── index.js │ ├── middlewares │ │ └── index.js │ ├── reducers │ │ ├── counter.js │ │ ├── images.js │ │ ├── index.js │ │ └── sum.js │ └── store │ │ └── config.js │ ├── server.js │ └── webpack.config.js ├── 5. more examples ├── 1. refactor │ ├── .babelrc │ ├── components │ │ ├── App.js │ │ ├── Examples.js │ │ ├── Examples02.js │ │ ├── Todos.js │ │ └── Youtube.js │ ├── containers │ │ └── examples01 │ │ │ ├── Counter.js │ │ │ ├── RandomImages.js │ │ │ └── Sum.js │ ├── index.html │ ├── index.js │ ├── package.json │ ├── redux │ │ ├── actions │ │ │ └── index.js │ │ ├── middlewares │ │ │ └── index.js │ │ ├── reducers │ │ │ ├── examples01 │ │ │ │ ├── counter.js │ │ │ │ ├── images.js │ │ │ │ └── sum.js │ │ │ └── index.js │ │ └── store │ │ │ └── config.js │ ├── server.js │ └── webpack.config.js ├── 2. todolist │ ├── .babelrc │ ├── components │ │ ├── App.js │ │ ├── Examples.js │ │ ├── Examples02.js │ │ ├── Todos.js │ │ └── Youtube.js │ ├── containers │ │ ├── examples01 │ │ │ ├── Counter.js │ │ │ ├── RandomImages.js │ │ │ └── Sum.js │ │ └── todos │ │ │ ├── AddTodo.js │ │ │ ├── Filter.js │ │ │ ├── FiltersList.js │ │ │ ├── Todo.js │ │ │ └── TodosList.js │ ├── index.html │ ├── index.js │ ├── package.json │ ├── redux │ │ ├── actions │ │ │ ├── index.js │ │ │ └── todos.js │ │ ├── middlewares │ │ │ └── index.js │ │ ├── reducers │ │ │ ├── examples01 │ │ │ │ ├── counter.js │ │ │ │ ├── images.js │ │ │ │ └── sum.js │ │ │ ├── index.js │ │ │ └── todos │ │ │ │ ├── todosFilter.js │ │ │ │ └── todosList.js │ │ └── store │ │ │ └── config.js │ ├── server.js │ └── webpack.config.js └── 3. youtube │ ├── .babelrc │ ├── components │ ├── App.js │ ├── Examples.js │ ├── Examples02.js │ ├── Todos.js │ └── Youtube.js │ ├── containers │ ├── examples01 │ │ ├── Counter.js │ │ ├── RandomImages.js │ │ └── Sum.js │ ├── todos │ │ ├── AddTodo.js │ │ ├── Filter.js │ │ ├── FiltersList.js │ │ ├── Todo.js │ │ └── TodosList.js │ └── youtube │ │ ├── List.js │ │ ├── ListItem.js │ │ ├── Search.js │ │ └── Video.js │ ├── index.html │ ├── index.js │ ├── package.json │ ├── redux │ ├── actions │ │ ├── index.js │ │ ├── todos.js │ │ └── youtube.js │ ├── middlewares │ │ └── index.js │ ├── reducers │ │ ├── examples01 │ │ │ ├── counter.js │ │ │ ├── images.js │ │ │ └── sum.js │ │ ├── index.js │ │ ├── todos │ │ │ ├── todosFilter.js │ │ │ └── todosList.js │ │ └── youtube │ │ │ ├── list.js │ │ │ ├── load.js │ │ │ └── video.js │ └── store │ │ └── config.js │ ├── server.js │ └── webpack.config.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | dist 5 | lib 6 | es 7 | coverage 8 | _book 9 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v01-normal Javascript.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redux basic example 5 | 6 | 7 |
8 |

9 | Clicked: 0 times 10 | 11 | 12 |

13 |
14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v06-exercise03-structure for a bigger project/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = function(a, b){ 11 | return { type: 'SUM', a:a, b:b }; 12 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v06-exercise03-structure for a bigger project/index.js: -------------------------------------------------------------------------------- 1 | // step 1.2 2 | var store = Redux.createStore(combineReducer) 3 | // ~end step 1.2 4 | // step 1.3 5 | 6 | function render() { 7 | var state = store.getState(); 8 | document.getElementById('value').innerHTML = state.count; 9 | document.getElementById('value2').innerHTML = state.sum; 10 | }; 11 | 12 | store.subscribe(render); 13 | // ~end step 1.3 14 | render(); 15 | 16 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v07-solution03-structure for a bigger project/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = function(a, b){ 11 | return { type: 'SUM', a:a, b:b }; 12 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v07-solution03-structure for a bigger project/index.js: -------------------------------------------------------------------------------- 1 | // step 1.2 2 | var store = Redux.createStore(combineReducer) 3 | // ~end step 1.2 4 | // step 1.3 5 | 6 | function render() { 7 | var state = store.getState(); 8 | document.getElementById('value').innerHTML = state.count; 9 | document.getElementById('value2').innerHTML = state.sum; 10 | }; 11 | 12 | store.subscribe(render); 13 | // ~end step 1.3 14 | render(); 15 | 16 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v07-solution03-structure for a bigger project/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = 0; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | 5 | nextState = DEFAULT_STATE;// Note1.2 6 | return nextState; 7 | } 8 | switch (action.type) { 9 | case 'DECREMENT': // look at Note2.1 10 | nextState = currentState - 1; 11 | return nextState;// Note2.2 12 | case 'INCREMENT': // look at Note2.1 13 | nextState = currentState + 1; 14 | return nextState;// Note2.2 15 | default: 16 | nextState = currentState; 17 | return nextState; 18 | } 19 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v07-solution03-structure for a bigger project/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action) 8 | } 9 | return nextState; 10 | } 11 | 12 | //~end step 2.2 -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v07-solution03-structure for a bigger project/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | return nextState;// Note2.2 12 | default: 13 | nextState = currentState; 14 | return nextState; 15 | } 16 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v08-middleware/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | var _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : function ( currentCount, cb ){ 4 | setTimeout(function(){ 5 | cb(currentCount + 1); 6 | }, 5000) 7 | } 8 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v08-middleware/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = function(a, b){ 11 | return { type: 'SUM', a:a, b:b }; 12 | } 13 | 14 | // ASYNC 15 | var asyncIncrease = function(dispatch, state){ 16 | dispatch({type:"INCREMENT_LOADING"}); 17 | _fakeServerApi.increaseCount(state.count.result, 18 | function(data){ 19 | dispatch({ type: 'INCREMENT' }); 20 | } 21 | ); 22 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v08-middleware/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | var state = store.getState() 8 | document.getElementById('value').innerHTML = state.count.result; 9 | document.getElementById('value2').innerHTML = state.sum; 10 | 11 | if(state.count.loading){ 12 | document.getElementById('status').innerHTML = "is loading..."; 13 | }else{ 14 | document.getElementById('status').innerHTML = "loaded"; 15 | } 16 | }; 17 | store.subscribe(render); 18 | // ~end step 1.3 19 | render(); 20 | 21 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v08-middleware/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = {result:0, loading:false}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'DECREMENT': // look at Note2.1 11 | nextState.result = currentState.result - 1; 12 | return nextState;// Note2.2 13 | case 'INCREMENT': // look at Note2.1 14 | nextState.result = currentState.result + 1; 15 | nextState.loading = false; 16 | return nextState;// Note2.2 17 | case 'INCREMENT_LOADING': // look at Note2.1 18 | nextState.loading = true; 19 | return nextState;// Note2.2 20 | default: 21 | nextState = currentState; 22 | return nextState; 23 | } 24 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v08-middleware/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action) 8 | } 9 | return nextState; 10 | } 11 | 12 | //~end step 2.2 -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v08-middleware/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v09-thunk middleware-exercise/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | var _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : function ( currentCount, cb ){ 4 | setTimeout(function(){ 5 | cb(currentCount + 1); 6 | }, 5000) 7 | } 8 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v09-thunk middleware-exercise/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = function(a, b){ 11 | return { type: 'SUM', a:a, b:b }; 12 | } 13 | 14 | // ASYNC 15 | var asyncIncrease = function(dispatch, state){ 16 | dispatch({type:"INCREMENT_LOADING"}); 17 | _fakeServerApi.increaseCount(state.count.result, 18 | function(data){ 19 | dispatch({ type: 'INCREMENT' }); 20 | } 21 | ); 22 | } 23 | 24 | var getRandomImages = function(dispatch, state){ 25 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 26 | $.getJSON(imgurAPI).done(function(data){ 27 | console.log('API data: ', data) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v09-thunk middleware-exercise/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | var state = store.getState() 8 | document.getElementById('value').innerHTML = state.count.result; 9 | document.getElementById('value2').innerHTML = state.sum; 10 | 11 | if(state.count.loading){ 12 | document.getElementById('status').innerHTML = "is loading..."; 13 | }else{ 14 | document.getElementById('status').innerHTML = "loaded"; 15 | } 16 | }; 17 | store.subscribe(render); 18 | // ~end step 1.3 19 | render(); 20 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v09-thunk middleware-exercise/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = {result:0, loading:false}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'DECREMENT': // look at Note2.1 11 | nextState.result = currentState.result - 1; 12 | return nextState;// Note2.2 13 | case 'INCREMENT': // look at Note2.1 14 | nextState.result = currentState.result + 1; 15 | nextState.loading = false; 16 | return nextState;// Note2.2 17 | case 'INCREMENT_LOADING': // look at Note2.1 18 | nextState.loading = true; 19 | return nextState;// Note2.2 20 | default: 21 | nextState = currentState; 22 | return nextState; 23 | } 24 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v09-thunk middleware-exercise/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action) 8 | } 9 | return nextState; 10 | } 11 | 12 | //~end step 2.2 -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v09-thunk middleware-exercise/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v10-solution.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeonardoDanielSu/redux-ld/a0e591daca427f0dbf0bac26750d6d4b9ac762ba/1. Redux & plain Javascript/v10-solution.docx -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v10-thunk middleware-solution/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | var _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : function ( currentCount, cb ){ 4 | setTimeout(function(){ 5 | cb(currentCount + 1); 6 | }, 5000) 7 | } 8 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v10-thunk middleware-solution/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = function(a, b){ 11 | return { type: 'SUM', a:a, b:b }; 12 | } 13 | 14 | // ASYNC 15 | var asyncIncrease = function(dispatch, state){ 16 | dispatch({type:"INCREMENT_LOADING"}); 17 | _fakeServerApi.increaseCount(state.count.result, 18 | function(data){ 19 | dispatch({ type: 'INCREMENT' }); 20 | } 21 | ); 22 | } 23 | 24 | var getRandomImages = function(dispatch, state){ 25 | dispatch({ type: 'IMAGES_LOADING' }); 26 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 27 | $.getJSON(imgurAPI).done(function(data){ 28 | dispatch({ type: 'IMAGES', data:data.data}); 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v10-thunk middleware-solution/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = {result:0, loading:false}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'DECREMENT': // look at Note2.1 11 | nextState.result = currentState.result - 1; 12 | return nextState;// Note2.2 13 | case 'INCREMENT': // look at Note2.1 14 | nextState.result = currentState.result + 1; 15 | nextState.loading = false; 16 | return nextState;// Note2.2 17 | case 'INCREMENT_LOADING': // look at Note2.1 18 | nextState.loading = true; 19 | return nextState;// Note2.2 20 | default: 21 | nextState = currentState; 22 | return nextState; 23 | } 24 | } -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v10-thunk middleware-solution/reducers/images.js: -------------------------------------------------------------------------------- 1 | function images(currentState, action){ 2 | var DEFAULT_STATE = {data:[], loading:"Please click the 'Random Images' button"}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'IMAGES': // look at Note2.1 11 | nextState.data = action.data 12 | nextState.loading = "loaded"; 13 | return nextState;// Note2.2 14 | case 'IMAGES_LOADING': // look at Note2.1 15 | nextState.loading = "loading..."; 16 | return nextState;// Note2.2 17 | default: 18 | nextState = currentState; 19 | return nextState; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v10-thunk middleware-solution/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action), 8 | images: images(nextState.images, action) 9 | } 10 | return nextState; 11 | } 12 | 13 | //~end step 2.2 14 | -------------------------------------------------------------------------------- /1. Redux & plain Javascript/v10-thunk middleware-solution/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } -------------------------------------------------------------------------------- /2. Redux & jquery/v01. convert to Jquery - exercise/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | var _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : function ( currentCount, cb ){ 4 | setTimeout(function(){ 5 | cb(currentCount + 1); 6 | }, 5000) 7 | } 8 | } -------------------------------------------------------------------------------- /2. Redux & jquery/v01. convert to Jquery - exercise/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = function(a, b){ 11 | return { type: 'SUM', a:a, b:b }; 12 | } 13 | 14 | // ASYNC 15 | var asyncIncrease = function(dispatch, state){ 16 | dispatch({type:"INCREMENT_LOADING"}); 17 | _fakeServerApi.increaseCount(state.count.result, 18 | function(data){ 19 | dispatch({ type: 'INCREMENT' }); 20 | } 21 | ); 22 | } 23 | 24 | var getRandomImages = function(dispatch, state){ 25 | dispatch({ type: 'IMAGES_LOADING' }); 26 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 27 | $.getJSON(imgurAPI).done(function(data){ 28 | dispatch({ type: 'IMAGES', data:data.data}); 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /2. Redux & jquery/v01. convert to Jquery - exercise/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | var state = store.getState() 8 | document.getElementById('value').innerHTML = state.count.result; 9 | document.getElementById('value2').innerHTML = state.sum; 10 | 11 | if(state.count.loading){ 12 | document.getElementById('status').innerHTML = "is loading..."; 13 | }else{ 14 | document.getElementById('status').innerHTML = "loaded"; 15 | } 16 | // image 17 | document.getElementById('imagesStatus').innerHTML = state.images.loading; 18 | if(state.images.loading =="loading…"){ 19 | $('#imagesList').text(""); 20 | } 21 | else if(state.images.loading =="loaded"){ 22 | for(var i=0; i< state.images.data.length; i++){ 23 | $('#imagesList').append( 24 | ""); 25 | } 26 | } 27 | 28 | }; 29 | store.subscribe(render); 30 | // ~end step 1.3 31 | render(); 32 | -------------------------------------------------------------------------------- /2. Redux & jquery/v01. convert to Jquery - exercise/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = {result:0, loading:false}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'DECREMENT': // look at Note2.1 11 | nextState.result = currentState.result - 1; 12 | return nextState;// Note2.2 13 | case 'INCREMENT': // look at Note2.1 14 | nextState.result = currentState.result + 1; 15 | nextState.loading = false; 16 | return nextState;// Note2.2 17 | case 'INCREMENT_LOADING': // look at Note2.1 18 | nextState.loading = true; 19 | return nextState;// Note2.2 20 | default: 21 | nextState = currentState; 22 | return nextState; 23 | } 24 | } -------------------------------------------------------------------------------- /2. Redux & jquery/v01. convert to Jquery - exercise/reducers/images.js: -------------------------------------------------------------------------------- 1 | function images(currentState, action){ 2 | var DEFAULT_STATE = {data:[], loading:"Please click the 'Random Images' button"}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'IMAGES': // look at Note2.1 11 | nextState.data = action.data 12 | nextState.loading = "loaded"; 13 | return nextState;// Note2.2 14 | case 'IMAGES_LOADING': // look at Note2.1 15 | nextState.loading = "loading..."; 16 | return nextState;// Note2.2 17 | default: 18 | nextState = currentState; 19 | return nextState; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /2. Redux & jquery/v01. convert to Jquery - exercise/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action), 8 | images: images(nextState.images, action) 9 | } 10 | return nextState; 11 | } 12 | 13 | //~end step 2.2 14 | -------------------------------------------------------------------------------- /2. Redux & jquery/v01. convert to Jquery - exercise/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | // funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } 22 | -------------------------------------------------------------------------------- /2. Redux & jquery/v02. convert to Jquery - solution/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | var _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : function ( currentCount, cb ){ 4 | setTimeout(function(){ 5 | cb(currentCount + 1); 6 | }, 5000) 7 | } 8 | } -------------------------------------------------------------------------------- /2. Redux & jquery/v02. convert to Jquery - solution/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = function(a, b){ 11 | return { type: 'SUM', a:a, b:b }; 12 | } 13 | 14 | // ASYNC 15 | var asyncIncrease = function(dispatch, state){ 16 | dispatch({type:"INCREMENT_LOADING"}); 17 | _fakeServerApi.increaseCount(state.count.result, 18 | function(data){ 19 | dispatch({ type: 'INCREMENT' }); 20 | } 21 | ); 22 | } 23 | 24 | var getRandomImages = function(dispatch, state){ 25 | dispatch({ type: 'IMAGES_LOADING' }); 26 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 27 | $.getJSON(imgurAPI).done(function(data){ 28 | dispatch({ type: 'IMAGES', data:data.data}); 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /2. Redux & jquery/v02. convert to Jquery - solution/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | var state = store.getState() 8 | $('#value').text(state.count.result); 9 | $('#value2').text(state.sum); 10 | 11 | if(state.count.loading){ 12 | $('#status').text("is loading..."); 13 | }else{ 14 | $('#status').text("loaded"); 15 | } 16 | // image 17 | $('#imagesStatus').text(state.images.loading); 18 | if(state.images.loading =="loading…"){ 19 | $('#imagesList').text(""); 20 | } 21 | else if(state.images.loading =="loaded"){ 22 | for(var i=0; i< state.images.data.length; i++){ 23 | $('#imagesList').append(""); 24 | } 25 | } 26 | 27 | }; 28 | store.subscribe(render); 29 | // ~end step 1.3 30 | render(); 31 | -------------------------------------------------------------------------------- /2. Redux & jquery/v02. convert to Jquery - solution/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = {result:0, loading:false}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'DECREMENT': // look at Note2.1 11 | nextState.result = currentState.result - 1; 12 | return nextState;// Note2.2 13 | case 'INCREMENT': // look at Note2.1 14 | nextState.result = currentState.result + 1; 15 | nextState.loading = false; 16 | return nextState;// Note2.2 17 | case 'INCREMENT_LOADING': // look at Note2.1 18 | nextState.loading = true; 19 | return nextState;// Note2.2 20 | default: 21 | nextState = currentState; 22 | return nextState; 23 | } 24 | } -------------------------------------------------------------------------------- /2. Redux & jquery/v02. convert to Jquery - solution/reducers/images.js: -------------------------------------------------------------------------------- 1 | function images(currentState, action){ 2 | var DEFAULT_STATE = {data:[], loading:"Please click the 'Random Images' button"}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'IMAGES': // look at Note2.1 11 | nextState.data = action.data 12 | nextState.loading = "loaded"; 13 | return nextState;// Note2.2 14 | case 'IMAGES_LOADING': // look at Note2.1 15 | nextState.loading = "loading..."; 16 | return nextState;// Note2.2 17 | default: 18 | nextState = currentState; 19 | return nextState; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /2. Redux & jquery/v02. convert to Jquery - solution/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action), 8 | images: images(nextState.images, action) 9 | } 10 | return nextState; 11 | } 12 | 13 | //~end step 2.2 14 | -------------------------------------------------------------------------------- /2. Redux & jquery/v02. convert to Jquery - solution/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | // funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } 22 | -------------------------------------------------------------------------------- /3. Redux & ES6/v01. Arrow function - exercise/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | var _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : function ( currentCount, cb ){ 4 | setTimeout(function(){ 5 | cb(currentCount + 1); 6 | }, 5000) 7 | } 8 | } -------------------------------------------------------------------------------- /3. Redux & ES6/v01. Arrow function - exercise/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = function(){ 3 | return { type: 'DECREMENT' }; 4 | } 5 | 6 | var increase = function(){ 7 | return { type: 'INCREMENT' }; 8 | } 9 | 10 | var getSum = (a, b) => ({ type: 'SUM', a:a, b:b }); 11 | 12 | // ASYNC 13 | var asyncIncrease = function(dispatch, state){ 14 | dispatch({type:"INCREMENT_LOADING"}); 15 | _fakeServerApi.increaseCount(state.count.result, 16 | function(data){ 17 | dispatch({ type: 'INCREMENT' }); 18 | } 19 | ); 20 | } 21 | 22 | var getRandomImages = function(dispatch, state){ 23 | dispatch({ type: 'IMAGES_LOADING' }); 24 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 25 | $.getJSON(imgurAPI).done(function(data){ 26 | dispatch({ type: 'IMAGES', data:data.data}); 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /3. Redux & ES6/v01. Arrow function - exercise/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | var state = store.getState() 8 | $('#value').text(state.count.result); 9 | $('#value2').text(state.sum); 10 | 11 | if(state.count.loading){ 12 | $('#status').text("is loading..."); 13 | }else{ 14 | $('#status').text("loaded"); 15 | } 16 | // image 17 | $('#imagesStatus').text(state.images.loading); 18 | if(state.images.loading =="loading…"){ 19 | $('#imagesList').text(""); 20 | } 21 | else if(state.images.loading =="loaded"){ 22 | for(var i=0; i< state.images.data.length; i++){ 23 | $('#imagesList').append(""); 24 | } 25 | } 26 | 27 | }; 28 | store.subscribe(render); 29 | // ~end step 1.3 30 | render(); 31 | -------------------------------------------------------------------------------- /3. Redux & ES6/v01. Arrow function - exercise/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = {result:0, loading:false}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'DECREMENT': // look at Note2.1 11 | nextState.result = currentState.result - 1; 12 | return nextState;// Note2.2 13 | case 'INCREMENT': // look at Note2.1 14 | nextState.result = currentState.result + 1; 15 | nextState.loading = false; 16 | return nextState;// Note2.2 17 | case 'INCREMENT_LOADING': // look at Note2.1 18 | nextState.loading = true; 19 | return nextState;// Note2.2 20 | default: 21 | nextState = currentState; 22 | return nextState; 23 | } 24 | } -------------------------------------------------------------------------------- /3. Redux & ES6/v01. Arrow function - exercise/reducers/images.js: -------------------------------------------------------------------------------- 1 | function images(currentState, action){ 2 | var DEFAULT_STATE = {data:[], loading:"Please click the 'Random Images' button"}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'IMAGES': // look at Note2.1 11 | nextState.data = action.data 12 | nextState.loading = "loaded"; 13 | return nextState;// Note2.2 14 | case 'IMAGES_LOADING': // look at Note2.1 15 | nextState.loading = "loading..."; 16 | return nextState;// Note2.2 17 | default: 18 | nextState = currentState; 19 | return nextState; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /3. Redux & ES6/v01. Arrow function - exercise/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action), 8 | images: images(nextState.images, action) 9 | } 10 | return nextState; 11 | } 12 | 13 | //~end step 2.2 14 | -------------------------------------------------------------------------------- /3. Redux & ES6/v01. Arrow function - exercise/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | // funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } 22 | -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | var _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : ( currentCount, cb ) => 4 | setTimeout(() => cb(currentCount + 1), 5000) 5 | } 6 | -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | var decrease = () => ({ type: 'DECREMENT' }); 3 | var increase = () => ({ type: 'INCREMENT' }); 4 | var getSum = (a, b) => ({ type: 'SUM', a:a, b:b }); 5 | 6 | // ASYNC 7 | var asyncIncrease = (dispatch, state) => { 8 | dispatch({type:"INCREMENT_LOADING"}); 9 | _fakeServerApi.increaseCount(state.count.result, 10 | data => dispatch({ type: 'INCREMENT' })); 11 | } 12 | 13 | var getRandomImages = (dispatch, state) => { 14 | dispatch({ type: 'IMAGES_LOADING' }); 15 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 16 | $.getJSON(imgurAPI).done(data => 17 | dispatch({ type: 'IMAGES', data:data.data})) 18 | } 19 | -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | var state = store.getState(); 8 | $('#value').text(state.count.result); 9 | $('#value2').text(state.sum); 10 | 11 | if(state.count.loading){ 12 | $('#status').text("is loading..."); 13 | }else{ 14 | $('#status').text("loaded"); 15 | } 16 | // image 17 | $('#imagesStatus').text(state.images.loading); 18 | if(state.images.loading =="loading…"){ 19 | $('#imagesList').text(""); 20 | } 21 | else if(state.images.loading =="loaded"){ 22 | for(var i=0; i< state.images.data.length; i++){ 23 | $('#imagesList').append(""); 24 | } 25 | } 26 | 27 | }; 28 | store.subscribe(render); 29 | // ~end step 1.3 30 | render(); 31 | -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(currentState, action){ 2 | var DEFAULT_STATE = {result:0, loading:false}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'DECREMENT': // look at Note2.1 11 | nextState.result = currentState.result - 1; 12 | return nextState;// Note2.2 13 | case 'INCREMENT': // look at Note2.1 14 | nextState.result = currentState.result + 1; 15 | nextState.loading = false; 16 | return nextState;// Note2.2 17 | case 'INCREMENT_LOADING': // look at Note2.1 18 | nextState.loading = true; 19 | return nextState;// Note2.2 20 | default: 21 | nextState = currentState; 22 | return nextState; 23 | } 24 | } -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/reducers/images.js: -------------------------------------------------------------------------------- 1 | function images(currentState, action){ 2 | var DEFAULT_STATE = {data:[], loading:"Please click the 'Random Images' button"}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'IMAGES': // look at Note2.1 11 | nextState.data = action.data 12 | nextState.loading = "loaded"; 13 | return nextState;// Note2.2 14 | case 'IMAGES_LOADING': // look at Note2.1 15 | nextState.loading = "loading..."; 16 | return nextState;// Note2.2 17 | default: 18 | nextState = currentState; 19 | return nextState; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | nextState = { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action), 8 | images: images(nextState.images, action) 9 | } 10 | return nextState; 11 | } 12 | 13 | //~end step 2.2 14 | -------------------------------------------------------------------------------- /3. Redux & ES6/v02. Arrow function - solution/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | // funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } 22 | -------------------------------------------------------------------------------- /3. Redux & ES6/v03. const, let examples/01let.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | const, let example 01 5 | 6 | 7 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /3. Redux & ES6/v03. const, let examples/02let.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | const, let example 02 5 | 6 | 7 | 8 | 9 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /3. Redux & ES6/v03. const, let examples/03const.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | const, let example 01 5 | 6 | 7 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /3. Redux & ES6/v04. default parameter, Object.assign()/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | const, let example 01 5 | 6 | 7 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | const _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : ( currentCount, cb ) => 4 | setTimeout(() => cb(currentCount + 1), 5000) 5 | } 6 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | const decrease = () => ({ type: 'DECREMENT' }); 3 | const increase = () => ({ type: 'INCREMENT' }); 4 | const getSum = (a, b) => ({ type: 'SUM', a:a, b:b }); 5 | 6 | // ASYNC 7 | const asyncIncrease = (dispatch, state) => { 8 | dispatch({type:"INCREMENT_LOADING"}); 9 | _fakeServerApi.increaseCount(state.count.result, 10 | data => dispatch({ type: 'INCREMENT' })); 11 | } 12 | 13 | const getRandomImages = (dispatch, state) => { 14 | dispatch({ type: 'IMAGES_LOADING' }); 15 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 16 | $.getJSON(imgurAPI).done(data => 17 | dispatch({ type: 'IMAGES', data:data.data})) 18 | } 19 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | const state = store.getState(); 8 | $('#value').text(state.count.result); 9 | $('#value2').text(state.sum); 10 | 11 | if(state.count.loading){ 12 | $('#status').text("is loading..."); 13 | }else{ 14 | $('#status').text("loaded"); 15 | } 16 | // image 17 | $('#imagesStatus').text(state.images.loading); 18 | if(state.images.loading =="loading…"){ 19 | $('#imagesList').text(""); 20 | } 21 | else if(state.images.loading =="loaded"){ 22 | for(let i=0; i< state.images.data.length; i++){ 23 | $('#imagesList').append(""); 24 | } 25 | } 26 | 27 | }; 28 | store.subscribe(render); 29 | // ~end step 1.3 30 | render(); 31 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return Object.assign({},state, 5 | {result: state.result - 1}); 6 | case 'INCREMENT': 7 | return Object.assign({},state, 8 | {result: state.result + 1, 9 | loading: false 10 | }); 11 | case 'INCREMENT_LOADING': 12 | return Object.assign({},state, 13 | { 14 | loading: true 15 | }); 16 | default: 17 | return state; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/reducers/images.js: -------------------------------------------------------------------------------- 1 | function images(currentState, action){ 2 | var DEFAULT_STATE = {data:[], loading:"Please click the 'Random Images' button"}; 3 | var nextState = Object.assign({},currentState); 4 | if (currentState === undefined) { // look at to Note 1.1 5 | 6 | nextState = DEFAULT_STATE;// Note1.2 7 | return nextState; 8 | } 9 | switch (action.type) { 10 | case 'IMAGES': // look at Note2.1 11 | nextState.data = action.data 12 | nextState.loading = "loaded"; 13 | return nextState;// Note2.2 14 | case 'IMAGES_LOADING': // look at Note2.1 15 | nextState.loading = "loading..."; 16 | return nextState;// Note2.2 17 | default: 18 | nextState = currentState; 19 | return nextState; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | return { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action), 8 | images: images(nextState.images, action) 9 | }; 10 | } 11 | 12 | //~end step 2.2 13 | -------------------------------------------------------------------------------- /3. Redux & ES6/v05. ES6 - exercise/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(currentState, action){ 2 | var DEFAULT_STATE = 3; 3 | if (currentState === undefined) { // look at to Note 1.1 4 | nextState = DEFAULT_STATE;// Note1.2 5 | return nextState; 6 | } 7 | switch (action.type) { 8 | 9 | case 'SUM': // look at Note2.1 10 | nextState = parseInt(action.a) + parseInt(action.b); 11 | // funcWithError() 12 | return nextState;// Note2.2 13 | default: 14 | nextState = currentState; 15 | return nextState; 16 | } 17 | } 18 | 19 | function funcWithError(){ 20 | throw Error('an error from sum') 21 | } 22 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/_fakeServerApi/index.js: -------------------------------------------------------------------------------- 1 | const _fakeServerApi = { 2 | // imitate the server API 3 | increaseCount : ( currentCount, cb ) => 4 | setTimeout(() => cb(currentCount + 1), 5000) 5 | } 6 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | const decrease = () => ({ type: 'DECREMENT' }); 3 | const increase = () => ({ type: 'INCREMENT' }); 4 | const getSum = (a, b) => ({ type: 'SUM', a:a, b:b }); 5 | 6 | // ASYNC 7 | const asyncIncrease = (dispatch, state) => { 8 | dispatch({type:"INCREMENT_LOADING"}); 9 | _fakeServerApi.increaseCount(state.count.result, 10 | data => dispatch({ type: 'INCREMENT' })); 11 | } 12 | 13 | const getRandomImages = (dispatch, state) => { 14 | dispatch({ type: 'IMAGES_LOADING' }); 15 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 16 | $.getJSON(imgurAPI).done(data => 17 | dispatch({ type: 'IMAGES', data:data.data})) 18 | } 19 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/index.js: -------------------------------------------------------------------------------- 1 | 2 | // step 1.2 3 | var store = Redux.createStore(combineReducer, Redux.applyMiddleware(logger, crashReporter, thunk)) 4 | // ~end step 1.2 5 | // step 1.3 6 | function render() { 7 | const state = store.getState(); 8 | $('#value').text(state.count.result); 9 | $('#value2').text(state.sum); 10 | 11 | if(state.count.loading){ 12 | $('#status').text("is loading..."); 13 | }else{ 14 | $('#status').text("loaded"); 15 | } 16 | // image 17 | $('#imagesStatus').text(state.images.loading); 18 | if(state.images.loading =="loading…"){ 19 | $('#imagesList').text(""); 20 | } 21 | else if(state.images.loading =="loaded"){ 22 | for(let i=0; i< state.images.data.length; i++){ 23 | $('#imagesList').append(""); 24 | } 25 | } 26 | 27 | }; 28 | store.subscribe(render); 29 | // ~end step 1.3 30 | render(); 31 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/reducers/counter.js: -------------------------------------------------------------------------------- 1 | function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return Object.assign({},state, 5 | {result: state.result - 1}); 6 | case 'INCREMENT': 7 | return Object.assign({},state, 8 | {result: state.result + 1, 9 | loading: false 10 | }); 11 | case 'INCREMENT_LOADING': 12 | return Object.assign({},state, 13 | { 14 | loading: true 15 | }); 16 | default: 17 | return state; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/reducers/images.js: -------------------------------------------------------------------------------- 1 | function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return Object.assign({},state,{ 6 | data: action.data, 7 | loading: "loaded" 8 | }); 9 | case 'IMAGES_LOADING': 10 | return Object.assign({},state,{ 11 | loading: "loading..." 12 | }); 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/reducers/index.js: -------------------------------------------------------------------------------- 1 | // step 2.2 2 | 3 | function combineReducer(currentState, action) { 4 | var nextState = Object.assign({},currentState); 5 | return { 6 | count:counter(nextState.count, action), 7 | sum: sum(nextState.sum, action), 8 | images: images(nextState.images, action) 9 | }; 10 | } 11 | 12 | //~end step 2.2 13 | -------------------------------------------------------------------------------- /3. Redux & ES6/v06. ES6 - solution/reducers/sum.js: -------------------------------------------------------------------------------- 1 | function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v01. simplest/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v01. simplest/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v01. simplest/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | class Examples extends Component { 5 | func01() { 6 | console.log("Hello from func01"); 7 | return "function of class" 8 | } 9 | render() { 10 | const func02 = function(){ 11 | console.log("Hello from func02"); 12 | return "function in render()" 13 | } 14 | return ( 15 |
16 |
Simple React
17 |
Hello, world
18 |
{ 1 + 1 }
19 |
{this.func01()}
20 |
{func02()}
21 |
22 | ) 23 | } 24 | } 25 | 26 | ReactDOM.render( 27 | , 28 | document.getElementById('root') 29 | ) 30 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v01. simplest/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v01. simplest/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v02. State; React DevTools/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v02. State; React DevTools/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v02. State; React DevTools/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | class Examples extends Component { 5 | constructor(props) { 6 | super(props) 7 | this.state = {count: 0, sum: 3, a:1, b: 2} 8 | this.decrease = this.decrease.bind(this); 9 | } 10 | decrease() { 11 | this.setState({count: this.state.count - 1}); 12 | } 13 | render() { 14 | console.log('Examples.render()'); 15 | return ( 16 |
17 |

React

18 | Clicked: {this.state.count} times 19 | 20 |

21 | this.setState({a: e.target.value})}/> 22 | + this.setState({b: e.target.value})}/> 23 | = {this.state.sum} 24 | 25 |

26 |

27 | ) 28 | } 29 | } 30 | 31 | ReactDOM.render( 32 | , 33 | document.getElementById('root') 34 | ) 35 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v02. State; React DevTools/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v02. State; React DevTools/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v03. child Component/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v03. child Component/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v03. child Component/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v03. child Component/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v04. ES6 - import, export, export default/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v04. ES6 - import, export, export default/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {count: 0} 6 | this.decrease = this.decrease.bind(this); 7 | } 8 | decrease() { 9 | this.setState({count: this.state.count - 1}); 10 | } 11 | render() { 12 | console.log('Counter.render()'); 13 | return ( 14 |
15 | Clicked: {this.state.count} times 16 | 17 |

18 |

19 | ) 20 | } 21 | } 22 | 23 | export const a = 'A'; 24 | export const b = {b:'B'}; -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v04. ES6 - import, export, export default/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {sum: 3, a:1, b: 2} 6 | } 7 | render() { 8 | console.log('Sum.render()'); 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 12 | + this.setState({b: e.target.value})}/> 13 | = {this.state.sum} 14 | 15 |

16 |

17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v04. ES6 - import, export, export default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v04. ES6 - import, export, export default/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import ReactDOM from 'react-dom' 3 | import Counter2, {a as a2, b} from './components/Counter' 4 | import Sum from './components/Sum' 5 | 6 | console.log(a2); 7 | console.log(b); 8 | 9 | class Examples extends Component { 10 | constructor(props) { 11 | super(props) 12 | 13 | } 14 | 15 | render() { 16 | console.log('Examples.render()'); 17 | return ( 18 |
19 |

React

20 | 21 | 22 |
23 | ) 24 | } 25 | } 26 | 27 | ReactDOM.render( 28 | , 29 | document.getElementById('root') 30 | ) 31 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v04. ES6 - import, export, export default/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v04. ES6 - import, export, export default/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v05. props/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v05. props/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {count: 0} 6 | this.decrease = this.decrease.bind(this); 7 | } 8 | decrease() { 9 | this.setState({count: this.state.count - 1}); 10 | this.props.countDesc('Click "decrease" button'); 11 | } 12 | render() { 13 | console.log('Counter.render()'); 14 | return ( 15 |
16 | Clicked: {this.state.count} times 17 | 18 |

19 |

20 | ) 21 | } 22 | } 23 | 24 | export const a = 'A'; 25 | export const b = {b:'B'}; -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v05. props/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {sum: 3, a:1, b: 2} 6 | } 7 | render() { 8 | console.log('Sum.render()'); 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 12 | + this.setState({b: e.target.value})}/> 13 | = {this.state.sum} 14 | 17 |

18 |

19 | ) 20 | } 21 | } -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v05. props/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v05. props/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v05. props/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v06. Stateless function & Key of list item/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v06. Stateless function & Key of list item/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {count: 0} 6 | this.decrease = this.decrease.bind(this); 7 | } 8 | decrease() { 9 | this.setState({count: this.state.count - 1}); 10 | } 11 | render() { 12 | console.log('Counter.render()'); 13 | return ( 14 |
15 | Clicked: {this.state.count} times 16 | 17 |

18 |

19 | ) 20 | } 21 | } 22 | 23 | export const a = 'A'; 24 | export const b = {b:'B'}; -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v06. Stateless function & Key of list item/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {sum: 3, a:1, b: 2} 6 | } 7 | render() { 8 | console.log('Sum.render()'); 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 12 | + this.setState({b: e.target.value})}/> 13 | = {this.state.sum} 14 | 17 |

18 |

19 | ) 20 | } 21 | } -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v06. Stateless function & Key of list item/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v06. Stateless function & Key of list item/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import ReactDOM from 'react-dom' 3 | import Counter2, {a as a2, b} from './components/Counter' 4 | import Sum from './components/Sum' 5 | import RandomImages from './components/RandomImages' 6 | class Describe extends Component { 7 | constructor(props) { 8 | super(props) 9 | 10 | } 11 | render() { 12 | console.log('Examples.render()'); 13 | return ( 14 |
15 |
16 | Describe: {this.props.desc}
17 |
18 | ) 19 | } 20 | } 21 | class Examples extends Component { 22 | constructor(props) { 23 | super(props) 24 | } 25 | render() { 26 | console.log('Examples.render()'); 27 | return ( 28 |
29 |

React

30 | 31 | 32 | 33 |
34 | ) 35 | } 36 | } 37 | 38 | ReactDOM.render( 39 | , 40 | document.getElementById('root') 41 | ) 42 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v06. Stateless function & Key of list item/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/1. only React/v06. Stateless function & Key of list item/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {count: 0} 6 | this.decrease = this.decrease.bind(this); 7 | } 8 | decrease() { 9 | this.setState({count: this.state.count - 1}); 10 | } 11 | render() { 12 | console.log('Counter.render()'); 13 | return ( 14 |
15 | Clicked: {this.state.count} times 16 | 17 |

18 |

19 | ) 20 | } 21 | } 22 | 23 | export const a = 'A'; 24 | export const b = {b:'B'}; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter2, {a as a2, b} from './Counter' 3 | import Sum from './Sum' 4 | import RandomImages from './RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | return ( 12 |
13 |

React

14 | 15 | 16 | 17 |
18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {sum: 3, a:1, b: 2} 6 | } 7 | render() { 8 | console.log('Sum.render()'); 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 12 | + this.setState({b: e.target.value})}/> 13 | = {this.state.sum} 14 | 17 |

18 |

19 | ) 20 | } 21 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | import Examples from './components/Examples' 3 | import store from './redux/store/config' 4 | 5 | import React from 'react' 6 | 7 | function render(){ 8 | ReactDOM.render( 9 | , 10 | document.getElementById('root') 11 | ) 12 | } 13 | render(); 14 | 15 | store.subscribe(render); -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a:a, b:b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | export const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | export const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | export const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/redux/reducers/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return Object.assign({},state, 5 | {result: state.result - 1}); 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/redux/reducers/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return Object.assign({},state,{ 6 | data: action.data, 7 | loading: "loaded" 8 | }); 9 | case 'IMAGES_LOADING': 10 | return Object.assign({},state,{ 11 | loading: "loading..." 12 | }); 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './counter' 2 | import images from './images' 3 | import sum from './sum' 4 | 5 | export default function combineReducer(currentState, action) { 6 | var nextState = Object.assign({},currentState); 7 | return { 8 | count:counter(nextState.count, action), 9 | sum: sum(nextState.sum, action), 10 | images: images(nextState.images, action) 11 | }; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/redux/reducers/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {logger, crashReporter, thunk} from '../middlewares/index' 4 | const store = createStore(combineReducer, 5 | applyMiddleware(logger, crashReporter, thunk)) 6 | export default store; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v01. step1 - insert Redux/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "env": { 4 | "development": { 5 | "presets": ["react-hmre"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | } 6 | render() { 7 | return ( 8 |
9 | Clicked: {this.props.count.result} times 10 | 11 |

12 |

13 | ) 14 | } 15 | } 16 | 17 | export const a = 'A'; 18 | export const b = {b:'B'}; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter2, {a as a2, b} from './Counter' 3 | import Sum from './Sum' 4 | import RandomImages from './RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | return ( 12 |
13 |

React

14 | 16 | 18 | 20 |
21 | ) 22 | } 23 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/components/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class RandomImages extends Component{ 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | 9 | return ( 10 |
11 | 13 |
CountStatus: 14 | 15 | {this.props.images.loading} 16 |

17 | 18 |

19 | ) 20 | } 21 | } 22 | function ImageList(props) { 23 | return ( 24 |
25 | {props.images.map((image)=> 26 | )} 29 |
30 | ) 31 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {a:1, b: 2} 6 | } 7 | render() { 8 | return ( 9 |
10 | this.setState({a: e.target.value})}/> 11 | + this.setState({b: e.target.value})}/> 12 | = {this.props.sum} 13 | 16 |

17 |

18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | import Examples from './components/Examples' 3 | import store from './redux/store/config' 4 | import {decrease, getSum, getRandomImages} from './redux/actions/index' 5 | import React from 'react' 6 | 7 | function render(){ 8 | ReactDOM.render( 9 | store.dispatch(decrease())} 11 | onSum = {(a,b)=> store.dispatch(getSum(a, b))} 12 | onRandomImages = {() => store.dispatch(getRandomImages)} 13 | />, 14 | document.getElementById('root') 15 | ) 16 | } 17 | render(); 18 | 19 | store.subscribe(render); -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a:a, b:b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | export const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | export const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | export const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/redux/reducers/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return Object.assign({},state, 5 | {result: state.result - 1}); 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/redux/reducers/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return Object.assign({},state,{ 6 | data: action.data, 7 | loading: "loaded" 8 | }); 9 | case 'IMAGES_LOADING': 10 | return Object.assign({},state,{ 11 | loading: "loading..." 12 | }); 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './counter' 2 | import images from './images' 3 | import sum from './sum' 4 | 5 | export default function combineReducer(currentState, action) { 6 | var nextState = Object.assign({},currentState); 7 | return { 8 | count:counter(nextState.count, action), 9 | sum: sum(nextState.sum, action), 10 | images: images(nextState.images, action) 11 | }; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/redux/reducers/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {logger, crashReporter, thunk} from '../middlewares/index' 4 | 5 | 6 | const store = createStore(combineReducer, {}, compose( 7 | applyMiddleware(logger, crashReporter, thunk), 8 | window.devToolsExtension ? window.devToolsExtension() : f => f 9 | )); 10 | 11 | export default store; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v02. step 2 - replace 'Component State' by 'Redux State'; Redux Dev Tools/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | } 6 | render() { 7 | const {count:{result},onDecrement} = this.props; 8 | return ( 9 |
10 | Clicked: {result} times 11 | 12 |

13 |

14 | ) 15 | } 16 | } 17 | 18 | export const a = 'A'; 19 | export const b = {b:'B'}; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter2, {a as a2, b} from './Counter' 3 | import Sum from './Sum' 4 | import RandomImages from './RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | const {value:{count,sum, images}, 12 | onDecrement, 13 | onSum, 14 | onRandomImages} = this.props; 15 | return ( 16 |
17 |

React

18 | 20 | 22 | 24 |
25 | ) 26 | } 27 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/components/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class RandomImages extends Component{ 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | const {images:{loading, data},onRandomImages} = this.props; 9 | return ( 10 |
11 | 13 |
CountStatus: 14 | 15 | {loading} 16 |

17 | 18 |

19 | ) 20 | } 21 | } 22 | function ImageList(props) { 23 | return ( 24 |
25 | {props.images.map((image)=> 26 | )} 29 |
30 | ) 31 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {a:1, b: 2} 6 | } 7 | render() { 8 | const {state:{a,b}, props:{sum, onSum}} = this; 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 13 | + this.setState({b: e.target.value})}/> 15 | = {sum} 16 | 17 |

18 |

19 | ) 20 | } 21 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | import Examples from './components/Examples' 3 | import store from './redux/store/config' 4 | import {decrease, getSum, getRandomImages} from './redux/actions/index' 5 | import React from 'react' 6 | 7 | 8 | function render(){ 9 | ReactDOM.render( 10 | store.dispatch(decrease())} 12 | onSum = {(a,b)=> store.dispatch(getSum(a, b))} 13 | onRandomImages = {() => store.dispatch(getRandomImages)} 14 | />, 15 | document.getElementById('root') 16 | ) 17 | } 18 | render(); 19 | 20 | store.subscribe(render); -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | export const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | export const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | export const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/redux/reducers/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/redux/reducers/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './counter' 2 | import images from './images' 3 | import sum from './sum' 4 | 5 | export default function combineReducer(currentState, action) { 6 | var nextState = {...currentState}; 7 | return { 8 | count:counter(nextState.count, action), 9 | sum: sum(nextState.sum, action), 10 | images: images(nextState.images, action) 11 | }; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/redux/reducers/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {logger, crashReporter, thunk} from '../middlewares/index' 4 | 5 | 6 | const store = createStore(combineReducer, {}, compose( 7 | applyMiddleware(logger, crashReporter, thunk), 8 | window.devToolsExtension ? window.devToolsExtension() : f => f 9 | )); 10 | 11 | export default store; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v03 ES6 - Object Destructuring, Shorthand property names, Spread Operator/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | } 6 | render() { 7 | const {count:{result},onDecrement} = this.props; 8 | return ( 9 |
10 | Clicked: {result} times 11 | 12 |

13 |

14 | ) 15 | } 16 | } 17 | 18 | import { connect } from 'react-redux' 19 | import { decrease } from '../redux/actions/index' 20 | 21 | const mapStateToProps = (state, ownProps) => { 22 | return { 23 | count: state.count 24 | } 25 | } 26 | 27 | const mapDispatchToProps = (dispatch, ownProps) => { 28 | return { 29 | onDecrement: () => dispatch(decrease()) 30 | } 31 | } 32 | 33 | // a container is a kind of component transfering state and dispatch 34 | // from Redux into its child Component. 35 | // For example: CounterContainer is a container, Counter is a child component 36 | const CounterContainer = connect( 37 | mapStateToProps, 38 | mapDispatchToProps 39 | )(Counter) 40 | 41 | export default CounterContainer -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter2, {a as a2, b} from './Counter' 3 | import Sum from './Sum' 4 | import RandomImages from './RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | // const {value:{count,sum, images}, 12 | // onDecrement, 13 | // onSum, 14 | // onRandomImages} = this.props; 15 | return ( 16 |
17 |

React

18 | 19 | 20 | 21 |
22 | ) 23 | } 24 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {a:1, b: 2} 6 | } 7 | render() { 8 | const {state:{a,b}, props:{sum, onSum}} = this; 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 13 | + this.setState({b: e.target.value})}/> 15 | = {sum} 16 | 17 |

18 |

19 | ) 20 | } 21 | } 22 | 23 | import { connect } from 'react-redux' 24 | import { getSum } from '../redux/actions/index' 25 | 26 | const mapStateToProps = (state, ownProps) => { 27 | return { 28 | sum: state.sum 29 | } 30 | } 31 | 32 | const mapDispatchToProps = (dispatch, ownProps) => { 33 | return { 34 | onSum: (a,b) => dispatch(getSum(a, b)) 35 | } 36 | } 37 | const SumContainer = connect( 38 | mapStateToProps, 39 | mapDispatchToProps 40 | )(Sum) 41 | 42 | export default SumContainer -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/index.js: -------------------------------------------------------------------------------- 1 | import {render} from 'react-dom' 2 | import Examples from './components/Examples' 3 | import store from './redux/store/config' 4 | //import {decrease, getSum, getRandomImages} from './redux/actions/index' 5 | import React from 'react' 6 | import { Provider } from 'react-redux' 7 | 8 | // function render(){ 9 | // ReactDOM.render( 10 | // store.dispatch(decrease())} 12 | // onSum = {(a,b)=> store.dispatch(getSum(a, b))} 13 | // onRandomImages = {() => store.dispatch(getRandomImages)} 14 | // />, 15 | // document.getElementById('root') 16 | // ) 17 | // } 18 | // render(); 19 | 20 | // store.subscribe(render); 21 | 22 | render( 23 | 24 | 25 | , 26 | document.getElementById('root') 27 | ) 28 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | export const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | export const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | export const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/redux/reducers/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/redux/reducers/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './counter' 2 | import images from './images' 3 | import sum from './sum' 4 | 5 | export default function combineReducer(currentState, action) { 6 | var nextState = {...currentState}; 7 | return { 8 | count:counter(nextState.count, action), 9 | sum: sum(nextState.sum, action), 10 | images: images(nextState.images, action) 11 | }; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/redux/reducers/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {logger, crashReporter, thunk} from '../middlewares/index' 4 | 5 | 6 | const store = createStore(combineReducer, {}, compose( 7 | applyMiddleware(logger, crashReporter, thunk), 8 | window.devToolsExtension ? window.devToolsExtension() : f => f 9 | )); 10 | 11 | export default store; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v04. react-redux -- Provider/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter2, {a as a2, b} from './Counter' 3 | import Sum from './Sum' 4 | import RandomImages from './RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | // const {value:{count,sum, images}, 12 | // onDecrement, 13 | // onSum, 14 | // onRandomImages} = this.props; 15 | return ( 16 |
17 |

React

18 | 19 | 20 | 21 |
22 | ) 23 | } 24 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/index.js: -------------------------------------------------------------------------------- 1 | import {render} from 'react-dom' 2 | import Examples from './components/Examples' 3 | import store from './redux/store/config' 4 | //import {decrease, getSum, getRandomImages} from './redux/actions/index' 5 | import React from 'react' 6 | import { Provider } from 'react-redux' 7 | 8 | // function render(){ 9 | // ReactDOM.render( 10 | // store.dispatch(decrease())} 12 | // onSum = {(a,b)=> store.dispatch(getSum(a, b))} 13 | // onRandomImages = {() => store.dispatch(getRandomImages)} 14 | // />, 15 | // document.getElementById('root') 16 | // ) 17 | // } 18 | // render(); 19 | 20 | // store.subscribe(render); 21 | 22 | render( 23 | 24 | 25 | , 26 | document.getElementById('root') 27 | ) 28 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | // middleware 2 | export const logger = store => next => action => { 3 | console.group('logger') 4 | console.log('currentState == ', store.getState()); 5 | console.info('next(action) // action == ', action) 6 | next(action); 7 | console.log('nextState == ', store.getState()); 8 | console.groupEnd('logger') 9 | } 10 | 11 | //second middleware 12 | export const crashReporter = store => next => action => { 13 | try{ 14 | next(action); 15 | }catch(err){ 16 | console.group('crashReporter'); 17 | console.error('error happen with action == ', action); 18 | console.error(err); 19 | console.groupEnd('crashReporter'); 20 | } 21 | 22 | } 23 | //third middleware 24 | export const thunk = store => next => action => { 25 | if(typeof action === 'function'){ 26 | action(store.dispatch, store.getState()); 27 | }else{ 28 | next(action); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/redux/reducers/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/redux/reducers/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './counter' 2 | import images from './images' 3 | import sum from './sum' 4 | 5 | export default function combineReducer(currentState, action) { 6 | var nextState = {...currentState}; 7 | return { 8 | count:counter(nextState.count, action), 9 | sum: sum(nextState.sum, action), 10 | images: images(nextState.images, action) 11 | }; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/redux/reducers/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {logger, crashReporter, thunk} from '../middlewares/index' 4 | 5 | 6 | const store = createStore(combineReducer, {}, compose( 7 | applyMiddleware(logger, crashReporter, thunk), 8 | window.devToolsExtension ? window.devToolsExtension() : f => f 9 | )); 10 | 11 | export default store; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v05. react-redux -- Provider (shorter)/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | } 6 | render() { 7 | const {count:{result},onDecrement} = this.props; 8 | return ( 9 |
10 | Clicked: {result} times 11 | 12 |

13 |

14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter from '../containers/Counter' 3 | import Sum from '../containers/Sum' 4 | import RandomImages from '../containers/RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | return ( 12 |
13 |

React

14 | 15 | 16 | 17 |
18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/components/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class RandomImages extends Component{ 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | const {images:{loading, data},onRandomImages} = this.props; 9 | return ( 10 |
11 | 13 |
CountStatus: 14 | 15 | {loading} 16 |

17 | 18 |

19 | ) 20 | } 21 | } 22 | function ImageList(props) { 23 | return ( 24 |
25 | {props.images.map((image)=> 26 | )} 29 |
30 | ) 31 | } 32 | 33 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {a:1, b: 2} 6 | } 7 | render() { 8 | const {state:{a,b}, props:{sum, onSum}} = this; 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 13 | + this.setState({b: e.target.value})}/> 15 | = {sum} 16 | 17 |

18 |

19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/containers/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { decrease } from '../redux/actions/index' 4 | import Counter from '../components/Counter' 5 | 6 | export default connect( 7 | (state, ownProps) => ({ 8 | count: state.count, 9 | prop2: state.prop // just an example in case of many properties 10 | }), 11 | { 12 | onDecrement: decrease, 13 | func2: () => {} // just an example in case you need many functions from dispatch 14 | } 15 | )(Counter) -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/containers/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import RandomImages from '../components/RandomImages' 3 | import { connect } from 'react-redux' 4 | import { getRandomImages } from '../redux/actions/index' 5 | 6 | export default connect( 7 | (state, ownProps) =>( { 8 | images: state.images 9 | }), 10 | {onRandomImages: () => getRandomImages} 11 | )(RandomImages) -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/containers/Sum.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { getSum } from '../redux/actions/index' 3 | import React, { Component } from 'react' 4 | import Sum from '../components/Sum' 5 | 6 | 7 | export default connect( 8 | (state, ownProps) => ( { 9 | sum: state.sum 10 | }), 11 | {onSum: (a,b) => getSum(a, b)} 12 | )(Sum) -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/index.js: -------------------------------------------------------------------------------- 1 | import {render} from 'react-dom' 2 | import Examples from './components/Examples' 3 | import store from './redux/store/config' 4 | import React from 'react' 5 | import { Provider } from 'react-redux' 6 | 7 | render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ) 13 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | export const crashReporter = store => next => action => { 2 | try{ 3 | next(action); 4 | }catch(err){ 5 | console.group('crashReporter'); 6 | console.error('error happen with action == ', action); 7 | console.error(err); 8 | console.groupEnd('crashReporter'); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/redux/reducers/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/redux/reducers/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './counter' 2 | import images from './images' 3 | import sum from './sum' 4 | import { combineReducers } from 'redux' 5 | 6 | export default combineReducers({ 7 | count:counter, 8 | sum, 9 | images 10 | }) -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/redux/reducers/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {crashReporter} from '../middlewares/index' 4 | import createLogger from 'redux-logger' 5 | import thunk from 'redux-thunk' 6 | 7 | const store = createStore(combineReducer, {}, compose( 8 | applyMiddleware(createLogger(), crashReporter, thunk), 9 | window.devToolsExtension ? window.devToolsExtension() : f => f 10 | )); 11 | 12 | export default store; -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.get("/", function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/2. React & Redux/v06. react-redux -- Container, combineReducers, middlewares (thunk, logger)/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link, browserHistory } from 'react-router' 3 | 4 | export default function App({ children }) { 5 | return ( 6 |
7 |
8 | Links: 9 | {' '} 10 | Home 11 | {' '} 12 | Examples02 13 | {' '} 14 | Examples02 with parameter 15 |
16 |
17 | 18 |
19 |
{children}
20 |
21 | ) 22 | } -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/components/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Counter extends Component{ 3 | constructor(props) { 4 | super(props) 5 | } 6 | render() { 7 | const {count:{result},onDecrement} = this.props; 8 | return ( 9 |
10 | Clicked: {result} times 11 | 12 |

13 |

14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter from '../containers/Counter' 3 | import Sum from '../containers/Sum' 4 | import RandomImages from '../containers/RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | return ( 12 |
13 |

React

14 | 15 | 16 | 17 |
18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/components/Examples02.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Examples02 extends Component { 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | console.log(this.props); 9 | return ( 10 |
11 |

Examples 02

12 | Hello, {this.props.params.name || 'world'} 13 |
14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/components/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class RandomImages extends Component{ 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | const {images:{loading, data},onRandomImages} = this.props; 9 | return ( 10 |
11 | 13 |
CountStatus: 14 | 15 | {loading} 16 |

17 | 18 |

19 | ) 20 | } 21 | } 22 | function ImageList(props) { 23 | return ( 24 |
25 | {props.images.map((image)=> 26 | )} 29 |
30 | ) 31 | } 32 | 33 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/components/Sum.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | export default class Sum extends Component{ 3 | constructor(props) { 4 | super(props) 5 | this.state = {a:1, b: 2} 6 | } 7 | render() { 8 | const {state:{a,b}, props:{sum, onSum}} = this; 9 | return ( 10 |
11 | this.setState({a: e.target.value})}/> 13 | + this.setState({b: e.target.value})}/> 15 | = {sum} 16 | 17 |

18 |

19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/containers/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { decrease } from '../redux/actions/index' 4 | import Counter from '../components/Counter' 5 | 6 | export default connect( 7 | (state, ownProps) => ({ 8 | count: state.count, 9 | prop2: state.prop // just an example in case of many properties 10 | }), 11 | { 12 | onDecrement: decrease, 13 | func2: () => {} // just an example in case you need many functions from dispatch 14 | } 15 | )(Counter) -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/containers/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import RandomImages from '../components/RandomImages' 3 | import { connect } from 'react-redux' 4 | import { getRandomImages } from '../redux/actions/index' 5 | 6 | export default connect( 7 | (state, ownProps) =>( { 8 | images: state.images 9 | }), 10 | {onRandomImages: () => getRandomImages} 11 | )(RandomImages) -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/containers/Sum.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { getSum } from '../redux/actions/index' 3 | import React, { Component } from 'react' 4 | import Sum from '../components/Sum' 5 | 6 | 7 | export default connect( 8 | (state, ownProps) => ( { 9 | sum: state.sum 10 | }), 11 | {onSum: (a,b) => getSum(a, b)} 12 | )(Sum) -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/index.js: -------------------------------------------------------------------------------- 1 | import {render} from 'react-dom' 2 | import App from './components/App' 3 | import Examples from './components/Examples' 4 | import Examples02 from './components/Examples02' 5 | import store from './redux/store/config' 6 | import React from 'react' 7 | import { Provider } from 'react-redux' 8 | import { Router, Route, IndexRoute, browserHistory } from 'react-router' 9 | import { syncHistoryWithStore } from 'react-router-redux' 10 | // render( 11 | // 12 | // 13 | // , 14 | // document.getElementById('root') 15 | // ) 16 | 17 | // Create an enhanced history that syncs navigation events with the store 18 | const history = syncHistoryWithStore(browserHistory, store) 19 | 20 | render( 21 | 22 | { /* Tell the Router to use our enhanced history */ } 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | , 31 | document.getElementById('root') 32 | ) -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | export const crashReporter = store => next => action => { 2 | try{ 3 | next(action); 4 | }catch(err){ 5 | console.group('crashReporter'); 6 | console.error('error happen with action == ', action); 7 | console.error(err); 8 | console.groupEnd('crashReporter'); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/redux/reducers/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/redux/reducers/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './counter' 2 | import images from './images' 3 | import sum from './sum' 4 | import { combineReducers } from 'redux' 5 | import {routerReducer } from 'react-router-redux' 6 | 7 | export default combineReducers({ 8 | count:counter, 9 | sum, 10 | images, 11 | routing: routerReducer 12 | }) -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/redux/reducers/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {crashReporter} from '../middlewares/index' 4 | import createLogger from 'redux-logger' 5 | import thunk from 'redux-thunk' 6 | 7 | const store = createStore(combineReducer, {}, compose( 8 | applyMiddleware(createLogger(), crashReporter, thunk), 9 | window.devToolsExtension ? window.devToolsExtension() : f => f 10 | )); 11 | 12 | export default store; -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.use(function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /4. Redux & React/3. React-router/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link, browserHistory } from 'react-router' 3 | 4 | export default function App({ children }) { 5 | return ( 6 |
7 |
8 | Links: 9 | {' '} 10 | Home 11 | {' '} 12 | Examples02 13 | {' '} 14 | Examples02 with parameter 15 |
16 |
17 | 18 | {' '} 19 | 20 | {' '} 21 | 22 |
23 |
24 |
{children}
25 |
26 | ) 27 | } -------------------------------------------------------------------------------- /5. more examples/1. refactor/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter from '../containers/examples01/Counter' 3 | import Sum from '../containers/examples01/Sum' 4 | import RandomImages from '../containers/examples01/RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | return ( 12 |
13 |

React

14 | 15 | 16 | 17 |
18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /5. more examples/1. refactor/components/Examples02.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Examples02 extends Component { 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | console.log(this.props); 9 | return ( 10 |
11 |

Examples 02

12 | Hello, {this.props.params.name || 'world'} 13 |
14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /5. more examples/1. refactor/components/Todos.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Todos extends Component { 4 | render() { 5 | return ( 6 |
7 |

Todo List

8 |
9 | ) 10 | } 11 | } -------------------------------------------------------------------------------- /5. more examples/1. refactor/components/Youtube.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Youtube extends Component { 4 | render() { 5 | return ( 6 |
7 |

Youtube

8 |
9 | ) 10 | } 11 | } -------------------------------------------------------------------------------- /5. more examples/1. refactor/containers/examples01/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { decrease } from '../../redux/actions/index' 4 | class Counter extends Component{ 5 | constructor(props) { 6 | super(props) 7 | } 8 | render() { 9 | const {count:{result},onDecrement} = this.props; 10 | return ( 11 |
12 | Clicked: {result} times 13 | 14 |

15 |

16 | ) 17 | } 18 | } 19 | 20 | export default connect( 21 | (state, ownProps) => ({ 22 | count: state.examples.count, 23 | prop2: state.prop // just an example in case of many properties 24 | }), 25 | { 26 | onDecrement: decrease, 27 | func2: () => {} // just an example in case you need many functions from dispatch 28 | } 29 | )(Counter) -------------------------------------------------------------------------------- /5. more examples/1. refactor/containers/examples01/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { getRandomImages } from '../../redux/actions/index' 4 | 5 | class RandomImages extends Component{ 6 | constructor(props) { 7 | super(props) 8 | } 9 | render() { 10 | const {images:{loading, data},onRandomImages} = this.props; 11 | return ( 12 |
13 | 15 |
CountStatus: 16 | 17 | {loading} 18 |

19 | 20 |

21 | ) 22 | } 23 | } 24 | function ImageList(props) { 25 | return ( 26 |
27 | {props.images.map((image)=> 28 | )} 31 |
32 | ) 33 | } 34 | 35 | export default connect( 36 | (state, ownProps) =>( { 37 | images: state.examples.images 38 | }), 39 | {onRandomImages: () => getRandomImages} 40 | )(RandomImages) -------------------------------------------------------------------------------- /5. more examples/1. refactor/containers/examples01/Sum.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { getSum } from '../../redux/actions/index' 3 | import React, { Component } from 'react' 4 | 5 | class Sum extends Component{ 6 | constructor(props) { 7 | super(props) 8 | this.state = {a:1, b: 2} 9 | } 10 | render() { 11 | const {state:{a,b}, props:{sum, onSum}} = this; 12 | return ( 13 |
14 | this.setState({a: e.target.value})}/> 16 | + this.setState({b: e.target.value})}/> 18 | = {sum} 19 | 20 |

21 |

22 | ) 23 | } 24 | } 25 | 26 | export default connect( 27 | (state, ownProps) => ( { 28 | sum: state.examples.sum 29 | }), 30 | {onSum: getSum} 31 | )(Sum) -------------------------------------------------------------------------------- /5. more examples/1. refactor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | export const crashReporter = store => next => action => { 2 | try{ 3 | next(action); 4 | }catch(err){ 5 | console.group('crashReporter'); 6 | console.error('error happen with action == ', action); 7 | console.error(err); 8 | console.groupEnd('crashReporter'); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /5. more examples/1. refactor/redux/reducers/examples01/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/redux/reducers/examples01/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/redux/reducers/examples01/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './examples01/counter' 2 | import images from './examples01/images' 3 | import sum from './examples01/sum' 4 | import { combineReducers } from 'redux' 5 | import {routerReducer } from 'react-router-redux' 6 | 7 | export default combineReducers({ 8 | examples: combineReducers({ 9 | count:counter, 10 | sum, 11 | images 12 | }), 13 | // todos: combineReducers({ 14 | 15 | // }), 16 | // youtube: combineReducers({ 17 | 18 | // }), 19 | routing: routerReducer 20 | }) -------------------------------------------------------------------------------- /5. more examples/1. refactor/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {crashReporter} from '../middlewares/index' 4 | import createLogger from 'redux-logger' 5 | import thunk from 'redux-thunk' 6 | 7 | const store = createStore(combineReducer, {}, compose( 8 | applyMiddleware(createLogger(), crashReporter, thunk), 9 | window.devToolsExtension ? window.devToolsExtension() : f => f 10 | )); 11 | 12 | export default store; -------------------------------------------------------------------------------- /5. more examples/1. refactor/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.use(function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /5. more examples/1. refactor/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link, browserHistory } from 'react-router' 3 | 4 | export default function App({ children }) { 5 | return ( 6 |
7 |
8 | Links: 9 | {' '} 10 | Home 11 | {' '} 12 | Examples02 13 | {' '} 14 | Examples02 with parameter 15 |
16 |
17 | 18 | {' '} 19 | 20 | {' '} 21 | 22 |
23 |
24 |
{children}
25 |
26 | ) 27 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter from '../containers/examples01/Counter' 3 | import Sum from '../containers/examples01/Sum' 4 | import RandomImages from '../containers/examples01/RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | return ( 12 |
13 |

React

14 | 15 | 16 | 17 |
18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/components/Examples02.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Examples02 extends Component { 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | console.log(this.props); 9 | return ( 10 |
11 |

Examples 02

12 | Hello, {this.props.params.name || 'world'} 13 |
14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/components/Todos.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import AddTodo from '../containers/todos/AddTodo' 3 | import TodosList from '../containers/todos/TodosList' 4 | import FiltersList from '../containers/todos/FiltersList' 5 | 6 | export default class Todos extends Component { 7 | render() { 8 | return ( 9 |
10 |

Todo List

11 | 12 | 13 | 14 |
15 | ) 16 | } 17 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/components/Youtube.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Youtube extends Component { 4 | render() { 5 | return ( 6 |
7 |

Youtube

8 |
9 | ) 10 | } 11 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/containers/examples01/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { decrease } from '../../redux/actions/index' 4 | class Counter extends Component{ 5 | constructor(props) { 6 | super(props) 7 | } 8 | render() { 9 | const {count:{result},onDecrement} = this.props; 10 | return ( 11 |
12 | Clicked: {result} times 13 | 14 |

15 |

16 | ) 17 | } 18 | } 19 | 20 | export default connect( 21 | (state, ownProps) => ({ 22 | count: state.examples.count, 23 | prop2: state.prop // just an example in case of many properties 24 | }), 25 | { 26 | onDecrement: decrease, 27 | func2: () => {} // just an example in case you need many functions from dispatch 28 | } 29 | )(Counter) -------------------------------------------------------------------------------- /5. more examples/2. todolist/containers/examples01/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { getRandomImages } from '../../redux/actions/index' 4 | 5 | class RandomImages extends Component{ 6 | constructor(props) { 7 | super(props) 8 | } 9 | render() { 10 | const {images:{loading, data},onRandomImages} = this.props; 11 | return ( 12 |
13 | 15 |
CountStatus: 16 | 17 | {loading} 18 |

19 | 20 |

21 | ) 22 | } 23 | } 24 | function ImageList(props) { 25 | return ( 26 |
27 | {props.images.map((image)=> 28 | )} 31 |
32 | ) 33 | } 34 | 35 | export default connect( 36 | (state, ownProps) =>( { 37 | images: state.examples.images 38 | }), 39 | {onRandomImages: () => getRandomImages} 40 | )(RandomImages) -------------------------------------------------------------------------------- /5. more examples/2. todolist/containers/examples01/Sum.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { getSum } from '../../redux/actions/index' 3 | import React, { Component } from 'react' 4 | 5 | class Sum extends Component{ 6 | constructor(props) { 7 | super(props) 8 | this.state = {a:1, b: 2} 9 | } 10 | render() { 11 | const {state:{a,b}, props:{sum, onSum}} = this; 12 | return ( 13 |
14 | this.setState({a: e.target.value})}/> 16 | + this.setState({b: e.target.value})}/> 18 | = {sum} 19 | 20 |

21 |

22 | ) 23 | } 24 | } 25 | 26 | export default connect( 27 | (state, ownProps) => ( { 28 | sum: state.examples.sum 29 | }), 30 | {onSum: getSum} 31 | )(Sum) -------------------------------------------------------------------------------- /5. more examples/2. todolist/containers/todos/AddTodo.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { addTodo } from '../../redux/actions/todos' 4 | class AddTodo extends Component { 5 | constructor(props) { 6 | super(props) 7 | this.state = {todo: ""}; 8 | } 9 | render() { 10 | const {state: {todo}} = this; 11 | const onAddTodo = (e) => { 12 | e.preventDefault() 13 | if (!todo.trim()) { 14 | return 15 | } 16 | this.props.addTodo(todo); 17 | this.setState({todo: ''}) 18 | } 19 | return ( 20 |
21 |
22 | this.setState({todo: e.target.value})}/> 24 | 27 |
28 |
29 | ) 30 | } 31 | } 32 | 33 | export default connect(null,{ 34 | addTodo 35 | })(AddTodo) 36 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/containers/todos/Filter.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { setTodoFilter } from '../../redux/actions/todos' 3 | import { connect } from 'react-redux' 4 | 5 | const Filter = ({ active, children, onFilter }) => { 6 | if (active) { 7 | return {children} 8 | } 9 | 10 | return ( 11 | { 13 | e.preventDefault() 14 | onFilter() 15 | }} 16 | > 17 | {children} 18 | 19 | ) 20 | } 21 | 22 | Filter.propTypes = { 23 | active: PropTypes.bool.isRequired, 24 | children: PropTypes.node.isRequired, 25 | onFilter: PropTypes.func.isRequired 26 | } 27 | 28 | export default connect( 29 | (state, ownProps) => { 30 | return { 31 | active: state.todos.todosFilter === ownProps.filter 32 | } 33 | }, 34 | (dispatch, ownProps) => { 35 | return { 36 | onFilter: () => { 37 | dispatch(setTodoFilter(ownProps.filter)) 38 | } 39 | } 40 | } 41 | )(Filter) 42 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/containers/todos/FiltersList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Filter from './Filter' 3 | 4 | const FiltersList = () => ( 5 |

6 | Show: 7 | {" "} 8 | 9 | All 10 | 11 | {", "} 12 | 13 | Active 14 | 15 | {", "} 16 | 17 | Completed 18 | 19 |

20 | ) 21 | export default FiltersList -------------------------------------------------------------------------------- /5. more examples/2. todolist/containers/todos/Todo.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes } from 'react' 2 | import { toggleTodo } from '../../redux/actions/todos' 3 | import { connect } from 'react-redux' 4 | 5 | const Todo = ({id, toggleTodo, completed, text}) => ( 6 |
  • toggleTodo(id) } 8 | style={{ 9 | textDecoration: completed ? 'line-through' : 'none' 10 | }} 11 | > 12 | {text} 13 |
  • 14 | ) 15 | 16 | Todo.propTypes = { 17 | toggleTodo: PropTypes.func.isRequired, 18 | completed: PropTypes.bool.isRequired, 19 | text: PropTypes.string.isRequired 20 | } 21 | 22 | export default connect( 23 | null, 24 | { 25 | toggleTodo 26 | } 27 | )(Todo) -------------------------------------------------------------------------------- /5. more examples/2. todolist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
    8 |
    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/actions/todos.js: -------------------------------------------------------------------------------- 1 | let nextTodoId = 0 2 | export const addTodo = (text) => { 3 | return { 4 | type: 'ADD_TODO', 5 | id: nextTodoId++, 6 | text 7 | } 8 | } 9 | 10 | export const setTodoFilter = (filter) => { 11 | return { 12 | type: 'SET_TODOS_FILTER', 13 | filter 14 | } 15 | } 16 | 17 | export const toggleTodo = (id) => { 18 | return { 19 | type: 'TOGGLE_TODO', 20 | id 21 | } 22 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | export const crashReporter = store => next => action => { 2 | try{ 3 | next(action); 4 | }catch(err){ 5 | console.group('crashReporter'); 6 | console.error('error happen with action == ', action); 7 | console.error(err); 8 | console.groupEnd('crashReporter'); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/reducers/examples01/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/reducers/examples01/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/reducers/examples01/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './examples01/counter' 2 | import images from './examples01/images' 3 | import sum from './examples01/sum' 4 | 5 | import todosList from './todos/todosList' 6 | import todosFilter from './todos/todosFilter' 7 | 8 | import { combineReducers } from 'redux' 9 | import {routerReducer } from 'react-router-redux' 10 | 11 | export default combineReducers({ 12 | examples: combineReducers({ 13 | count:counter, 14 | sum, 15 | images 16 | }), 17 | todos: combineReducers({ 18 | todosList, 19 | todosFilter 20 | }), 21 | // youtube: combineReducers({ 22 | // }), 23 | routing: routerReducer 24 | }) -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/reducers/todos/todosFilter.js: -------------------------------------------------------------------------------- 1 | const todosFilter = (state = 'SHOW_ALL', action) => { 2 | switch (action.type) { 3 | case 'SET_TODOS_FILTER': 4 | return action.filter 5 | default: 6 | return state 7 | } 8 | } 9 | 10 | export default todosFilter 11 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/reducers/todos/todosList.js: -------------------------------------------------------------------------------- 1 | export default function (state = [], action) { 2 | switch (action.type) { 3 | case 'ADD_TODO': 4 | const newTodo = { 5 | id: action.id, 6 | text: action.text, 7 | completed: false 8 | } 9 | return [ 10 | ...state, 11 | newTodo 12 | ] 13 | case 'TOGGLE_TODO': 14 | return state.map(todo => { 15 | if (todo.id !== action.id) { 16 | return todo 17 | } 18 | 19 | return Object.assign({}, todo, { 20 | completed: !todo.completed 21 | }) 22 | }) 23 | default: 24 | return state 25 | } 26 | } -------------------------------------------------------------------------------- /5. more examples/2. todolist/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {crashReporter} from '../middlewares/index' 4 | import createLogger from 'redux-logger' 5 | import thunk from 'redux-thunk' 6 | 7 | const store = createStore(combineReducer, {}, compose( 8 | applyMiddleware(createLogger(), crashReporter, thunk), 9 | window.devToolsExtension ? window.devToolsExtension() : f => f 10 | )); 11 | 12 | export default store; -------------------------------------------------------------------------------- /5. more examples/2. todolist/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.use(function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /5. more examples/2. todolist/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"], 3 | "plugins": ["transform-object-rest-spread"], 4 | "env": { 5 | "development": { 6 | "presets": ["react-hmre"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link, browserHistory } from 'react-router' 3 | 4 | export default function App({ children }) { 5 | return ( 6 |
    7 |
    8 | Links: 9 | {' '} 10 | Home 11 | {' '} 12 | Examples02 13 | {' '} 14 | Examples02 with parameter 15 |
    16 |
    17 | 18 | {' '} 19 | 20 | {' '} 21 | 22 |
    23 |
    24 |
    {children}
    25 |
    26 | ) 27 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/components/Examples.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Counter from '../containers/examples01/Counter' 3 | import Sum from '../containers/examples01/Sum' 4 | import RandomImages from '../containers/examples01/RandomImages' 5 | 6 | export default class Examples extends Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | render() { 11 | return ( 12 |
    13 |

    React

    14 | 15 | 16 | 17 |
    18 | ) 19 | } 20 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/components/Examples02.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class Examples02 extends Component { 4 | constructor(props) { 5 | super(props) 6 | } 7 | render() { 8 | console.log(this.props); 9 | return ( 10 |
    11 |

    Examples 02

    12 | Hello, {this.props.params.name || 'world'} 13 |
    14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/components/Todos.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import AddTodo from '../containers/todos/AddTodo' 3 | import TodosList from '../containers/todos/TodosList' 4 | import FiltersList from '../containers/todos/FiltersList' 5 | 6 | export default class Todos extends Component { 7 | render() { 8 | return ( 9 |
    10 |

    Todo List

    11 | 12 | 13 | 14 |
    15 | ) 16 | } 17 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/components/Youtube.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Search from '../containers/youtube/Search' 3 | import Video from '../containers/youtube/Video' 4 | import List from '../containers/youtube/List' 5 | 6 | export default class Youtube extends Component { 7 | render() { 8 | return ( 9 |
    10 |

    Youtube

    11 | 12 |
    15 | ) 16 | } 17 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/examples01/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { decrease } from '../../redux/actions/index' 4 | class Counter extends Component{ 5 | constructor(props) { 6 | super(props) 7 | } 8 | render() { 9 | const {count:{result},onDecrement} = this.props; 10 | return ( 11 |
    12 | Clicked: {result} times 13 | 14 |

    15 |

    16 | ) 17 | } 18 | } 19 | 20 | export default connect( 21 | (state, ownProps) => ({ 22 | count: state.examples.count, 23 | prop2: state.prop // just an example in case of many properties 24 | }), 25 | { 26 | onDecrement: decrease, 27 | func2: () => {} // just an example in case you need many functions from dispatch 28 | } 29 | )(Counter) -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/examples01/RandomImages.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { getRandomImages } from '../../redux/actions/index' 4 | 5 | class RandomImages extends Component{ 6 | constructor(props) { 7 | super(props) 8 | } 9 | render() { 10 | const {images:{loading, data},onRandomImages} = this.props; 11 | return ( 12 |
    13 | 15 |
    CountStatus: 16 | 17 | {loading} 18 |

    19 | 20 |

    21 | ) 22 | } 23 | } 24 | function ImageList(props) { 25 | return ( 26 |
    27 | {props.images.map((image)=> 28 | )} 31 |
    32 | ) 33 | } 34 | 35 | export default connect( 36 | (state, ownProps) =>( { 37 | images: state.examples.images 38 | }), 39 | {onRandomImages: () => getRandomImages} 40 | )(RandomImages) -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/examples01/Sum.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { getSum } from '../../redux/actions/index' 3 | import React, { Component } from 'react' 4 | 5 | class Sum extends Component{ 6 | constructor(props) { 7 | super(props) 8 | this.state = {a:1, b: 2} 9 | } 10 | render() { 11 | const {state:{a,b}, props:{sum, onSum}} = this; 12 | return ( 13 |
    14 | this.setState({a: e.target.value})}/> 16 | + this.setState({b: e.target.value})}/> 18 | = {sum} 19 | 20 |

    21 |

    22 | ) 23 | } 24 | } 25 | 26 | export default connect( 27 | (state, ownProps) => ( { 28 | sum: state.examples.sum 29 | }), 30 | {onSum: getSum} 31 | )(Sum) -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/todos/AddTodo.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { addTodo } from '../../redux/actions/todos' 4 | class AddTodo extends Component { 5 | constructor(props) { 6 | super(props) 7 | this.state = {todo: ""}; 8 | } 9 | render() { 10 | const {state: {todo}} = this; 11 | const onAddTodo = (e) => { 12 | e.preventDefault() 13 | if (!todo.trim()) { 14 | return 15 | } 16 | this.props.addTodo(todo); 17 | this.setState({todo: ''}) 18 | } 19 | return ( 20 |
    21 |
    22 | this.setState({todo: e.target.value})}/> 24 | 27 |
    28 |
    29 | ) 30 | } 31 | } 32 | 33 | export default connect(null,{ 34 | addTodo 35 | })(AddTodo) 36 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/todos/Filter.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { setTodoFilter } from '../../redux/actions/todos' 3 | import { connect } from 'react-redux' 4 | 5 | const Filter = ({ active, children, onFilter }) => { 6 | if (active) { 7 | return {children} 8 | } 9 | 10 | return ( 11 | { 13 | e.preventDefault() 14 | onFilter() 15 | }} 16 | > 17 | {children} 18 | 19 | ) 20 | } 21 | 22 | Filter.propTypes = { 23 | active: PropTypes.bool.isRequired, 24 | children: PropTypes.node.isRequired, 25 | onFilter: PropTypes.func.isRequired 26 | } 27 | 28 | export default connect( 29 | (state, ownProps) => { 30 | return { 31 | active: state.todos.todosFilter === ownProps.filter 32 | } 33 | }, 34 | (dispatch, ownProps) => { 35 | return { 36 | onFilter: () => { 37 | dispatch(setTodoFilter(ownProps.filter)) 38 | } 39 | } 40 | } 41 | )(Filter) 42 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/todos/FiltersList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Filter from './Filter' 3 | 4 | const FiltersList = () => ( 5 |

    6 | Show: 7 | {" "} 8 | 9 | All 10 | 11 | {", "} 12 | 13 | Active 14 | 15 | {", "} 16 | 17 | Completed 18 | 19 |

    20 | ) 21 | export default FiltersList -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/todos/Todo.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes } from 'react' 2 | import { toggleTodo } from '../../redux/actions/todos' 3 | import { connect } from 'react-redux' 4 | 5 | const Todo = ({id, toggleTodo, completed, text}) => ( 6 |
  • toggleTodo(id) } 8 | style={{ 9 | textDecoration: completed ? 'line-through' : 'none' 10 | }} 11 | > 12 | {text} 13 |
  • 14 | ) 15 | 16 | Todo.propTypes = { 17 | toggleTodo: PropTypes.func.isRequired, 18 | completed: PropTypes.bool.isRequired, 19 | text: PropTypes.string.isRequired 20 | } 21 | 22 | export default connect( 23 | null, 24 | { 25 | toggleTodo 26 | } 27 | )(Todo) -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/youtube/List.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes } from 'react' 2 | import { connect } from 'react-redux' 3 | import ListItem from './ListItem' 4 | 5 | class List extends Component { 6 | render() { 7 | const {props:{list}} = this; 8 | return ( 9 |
      10 | { 11 | list.map(video => { 12 | const { id:{videoId} } = video; 13 | return() 14 | }) 15 | } 16 |
    17 | ) 18 | } 19 | } 20 | 21 | export default connect( (state) =>({ 22 | list: state.youtube.youtubeList 23 | }) 24 | )(List) 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/youtube/ListItem.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes } from 'react' 2 | import { connect } from 'react-redux' 3 | import {setVideo } from '../../redux/actions/youtube' 4 | 5 | 6 | class ListItem extends Component { 7 | render() { 8 | const { id: {videoId}, 9 | snippet: {title, description, thumbnails: {default: {url}}}} = this.props.video; 10 | const onVideo = (event) => { 11 | event.preventDefault(); 12 | this.props.setVideo(this.props.video) 13 | window.scrollTo(0, 0); 14 | } 15 | return ( 16 | 17 |

    {title}

    18 |
    {description}
    19 | 20 |
    21 | ) 22 | } 23 | } 24 | 25 | export default connect(null, 26 | { 27 | setVideo 28 | } 29 | )(ListItem) -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/youtube/Search.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import {search } from '../../redux/actions/youtube' 4 | class Search extends Component { 5 | constructor(props) { 6 | super(props) 7 | this.state = {term: ""} 8 | } 9 | render() { 10 | const {state:{term}} = this; 11 | const onSetTerm = (e) => { 12 | e.preventDefault() 13 | this.props.onSearch(term); 14 | } 15 | return ( 16 |
    17 |
    18 | this.setState({term: e.target.value})}/> 20 | 23 |
    24 |
    25 | ) 26 | } 27 | } 28 | function mapDispatchToProps(dispatch){ 29 | return {onSearch: (term) => dispatch(search.bind(null,term))} 30 | } 31 | export default connect(null, 32 | mapDispatchToProps 33 | )(Search) 34 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/containers/youtube/Video.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes } from 'react' 2 | import { connect } from 'react-redux' 3 | class Video extends Component { 4 | render() { 5 | const {props:{video}} = this; 6 | if(!video){ 7 | return
    8 | } 9 | const { id:{videoId} } = video; 10 | return ( 11 |

    12 |
    13 | 17 |

    18 | ) 19 | } 20 | } 21 | 22 | export default connect( (state)=>({ 23 | video: state.youtube.video 24 | }), 25 | null 26 | )(Video) 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React example 5 | 6 | 7 |
    8 |
    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const decrease = () => ({ type: 'DECREMENT' }); 3 | 4 | export const getSum = (a, b) => ({ type: 'SUM', a, b }); 5 | 6 | export const getRandomImages = (dispatch, state) => { 7 | dispatch({ type: 'IMAGES_LOADING' }); 8 | var imgurAPI = "https://api.imgur.com/3/gallery/random/random/1"; 9 | $.getJSON(imgurAPI).done(data => 10 | dispatch({ type: 'IMAGES', data:data.data})) 11 | } 12 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/actions/todos.js: -------------------------------------------------------------------------------- 1 | let nextTodoId = 0 2 | export const addTodo = (text) => { 3 | return { 4 | type: 'ADD_TODO', 5 | id: nextTodoId++, 6 | text 7 | } 8 | } 9 | 10 | export const setTodoFilter = (filter) => { 11 | return { 12 | type: 'SET_TODOS_FILTER', 13 | filter 14 | } 15 | } 16 | 17 | export const toggleTodo = (id) => { 18 | return { 19 | type: 'TOGGLE_TODO', 20 | id 21 | } 22 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/actions/youtube.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export const setList = (list) => ({ type: 'YOUTUBE_SEARCH_LOADED', list }); 3 | export const setTerm = () => ({ type: 'YOUTUBE_TERM' }); 4 | export const setVideo = (video) => ({ type: 'YOUTUBE_VIDEO', video }); 5 | 6 | export const search = (term, dispatch, state) => { 7 | dispatch( {type: 'YOUTUBE_SEARCH_LOADING'} ); 8 | const MAX = 20; 9 | const API_KEY = 'AIzaSyAY7wfv-FJ965RdnPjAxXNScS0VyJmsvZo'; 10 | let api = 'https://www.googleapis.com/youtube/v3/search'; 11 | api = `${api}?part=snippet&q=${term}&maxResults=${MAX}&order=viewCount&key=${API_KEY}`; 12 | $.getJSON(api).done(data =>{ 13 | const list = data.items.filter( (d) => d.id && d.id.videoId ); 14 | dispatch(setList(list)); 15 | dispatch(setVideo(null)); 16 | }) 17 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/middlewares/index.js: -------------------------------------------------------------------------------- 1 | export const crashReporter = store => next => action => { 2 | try{ 3 | next(action); 4 | }catch(err){ 5 | console.group('crashReporter'); 6 | console.error('error happen with action == ', action); 7 | console.error(err); 8 | console.groupEnd('crashReporter'); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/examples01/counter.js: -------------------------------------------------------------------------------- 1 | export default function counter(state = {result:0, loading:false}, action){ 2 | switch (action.type) { 3 | case 'DECREMENT': 4 | return {...state, 5 | result: state.result - 1}; 6 | default: 7 | return state; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/examples01/images.js: -------------------------------------------------------------------------------- 1 | export default function images(state = {data:[], 2 | loading:"Please click the 'Random Images' button"}, action){ 3 | switch (action.type) { 4 | case 'IMAGES': 5 | return {...state, 6 | data: action.data, 7 | loading: "loaded" 8 | }; 9 | case 'IMAGES_LOADING': 10 | return {...state, 11 | loading: "loading..." 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/examples01/sum.js: -------------------------------------------------------------------------------- 1 | export default function sum(state = 3, action){ 2 | switch (action.type) { 3 | case 'SUM': 4 | return parseInt(action.a) + parseInt(action.b); 5 | default: 6 | return state; 7 | } 8 | } 9 | 10 | function funcWithError(){ 11 | throw Error('an error from sum') 12 | } 13 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import counter from './examples01/counter' 2 | import images from './examples01/images' 3 | import sum from './examples01/sum' 4 | 5 | import todosList from './todos/todosList' 6 | import todosFilter from './todos/todosFilter' 7 | 8 | import youtubeList from './youtube/list' 9 | import youtubeVideo from './youtube/video' 10 | import youtubeLoad from './youtube/load' 11 | 12 | import { combineReducers } from 'redux' 13 | import {routerReducer } from 'react-router-redux' 14 | 15 | export default combineReducers({ 16 | examples: combineReducers({ 17 | count:counter, 18 | sum, 19 | images 20 | }), 21 | todos: combineReducers({ 22 | todosList, 23 | todosFilter 24 | }), 25 | youtube: combineReducers({ 26 | youtubeList, 27 | video: youtubeVideo, 28 | load: youtubeLoad 29 | }), 30 | routing: routerReducer 31 | }) -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/todos/todosFilter.js: -------------------------------------------------------------------------------- 1 | const todosFilter = (state = 'SHOW_ALL', action) => { 2 | switch (action.type) { 3 | case 'SET_TODOS_FILTER': 4 | return action.filter 5 | default: 6 | return state 7 | } 8 | } 9 | 10 | export default todosFilter 11 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/todos/todosList.js: -------------------------------------------------------------------------------- 1 | export default function (state = [], action) { 2 | switch (action.type) { 3 | case 'ADD_TODO': 4 | const newTodo = { 5 | id: action.id, 6 | text: action.text, 7 | completed: false 8 | } 9 | return [ 10 | ...state, 11 | newTodo 12 | ] 13 | case 'TOGGLE_TODO': 14 | return state.map(todo => { 15 | if (todo.id !== action.id) { 16 | return todo 17 | } 18 | 19 | return Object.assign({}, todo, { 20 | completed: !todo.completed 21 | }) 22 | }) 23 | default: 24 | return state 25 | } 26 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/youtube/list.js: -------------------------------------------------------------------------------- 1 | export default (state = [], action) => { 2 | switch (action.type) { 3 | case 'YOUTUBE_SEARCH_LOADED': 4 | return action.list 5 | default: 6 | return state 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/youtube/load.js: -------------------------------------------------------------------------------- 1 | export default (state = 'not search yet', action) => { 2 | switch (action.type) { 3 | case 'YOUTUBE_SEARCH_LOADING': 4 | return 'loading' 5 | case 'YOUTUBE_SEARCH_LOADED': 6 | return 'loaded' 7 | default: 8 | return state 9 | } 10 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/reducers/youtube/video.js: -------------------------------------------------------------------------------- 1 | export default (state = null, action) => { 2 | switch (action.type) { 3 | case 'YOUTUBE_VIDEO': 4 | return action.video 5 | default: 6 | return state 7 | } 8 | } -------------------------------------------------------------------------------- /5. more examples/3. youtube/redux/store/config.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose} from 'redux' 2 | import combineReducer from '../reducers/index' 3 | import {crashReporter} from '../middlewares/index' 4 | import createLogger from 'redux-logger' 5 | import thunk from 'redux-thunk' 6 | 7 | const store = createStore(combineReducer, {}, compose( 8 | applyMiddleware(createLogger(), crashReporter, thunk), 9 | window.devToolsExtension ? window.devToolsExtension() : f => f 10 | )); 11 | 12 | export default store; -------------------------------------------------------------------------------- /5. more examples/3. youtube/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var webpackDevMiddleware = require('webpack-dev-middleware') 3 | var webpackHotMiddleware = require('webpack-hot-middleware') 4 | var config = require('./webpack.config') 5 | 6 | var app = new (require('express'))() 7 | var port = 3000 8 | 9 | var compiler = webpack(config) 10 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })) 11 | app.use(webpackHotMiddleware(compiler)) 12 | 13 | app.use(function(req, res) { 14 | res.sendFile(__dirname + '/index.html') 15 | }) 16 | 17 | app.listen(port, function(error) { 18 | if (error) { 19 | console.error(error) 20 | } else { 21 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /5. more examples/3. youtube/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | devtool: 'cheap-module-eval-source-map', 6 | entry: [ 7 | 'webpack-hot-middleware/client', 8 | './index' 9 | ], 10 | output: { 11 | path: path.join(__dirname, 'dist'), 12 | filename: 'bundle.js', 13 | publicPath: '/static/' 14 | }, 15 | plugins: [ 16 | new webpack.optimize.OccurenceOrderPlugin(), 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loaders: [ 'babel' ], 24 | exclude: /node_modules/, 25 | include: __dirname 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # redux-ld 2 | This git repository is created for the course "React Redux React-Router: From Beginner to Paid Professional" in https://www.udemy.com/react-redux-react-router/ 3 | --------------------------------------------------------------------------------