├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── example ├── app.js ├── bundle.js ├── components │ ├── AddTodo.js │ ├── Footer.js │ ├── VisibleTodoList.js │ └── store.js └── index.html ├── index.js ├── lib ├── combineReducers.js ├── connect.js ├── createStore.js └── polyfill.js ├── package.json ├── test ├── test-combineReducers.js ├── test-connect.js └── test-createStore.js └── tutorial ├── bundle-example1.js ├── bundle-example2.js ├── bundle-example3.js ├── bundle-example4.js ├── bundle-example5.js ├── bundle-example6.js ├── example0.js ├── example1-react-withoutClass.js ├── example1-react.js ├── example1.js ├── example2-react.js ├── example3-react.js ├── example4-react.js ├── example5-react.js ├── example6-react.js ├── index-example1-react-withoutClass.html ├── index-example2.html ├── index-example3.html ├── index-example4.html ├── index-example5.html └── index-example6.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5" 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | REDUX-ES5 LICENSE 3 | ================= 4 | 5 | MIT License 6 | 7 | Copyright (c) [2016] [David Wee] 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/rook2pawn/redux-es5.svg?branch=master)](https://travis-ci.org/rook2pawn/redux-es5) 2 | 3 | redux-es5 4 | ========= 5 | 6 | Redux, with just es5. Fully supports connect bindings to React. 7 | 8 | Intro 9 | ===== 10 | 11 | See the [example](../master/example) directory for a fully separated component app backed with connect on the redux-es5 store. 12 | 13 | You can open the [the web page](../master/example/index.html) in your browser to see the application in action. Compiled with [browserify](https://github.com/substack/browserify) 14 | 15 | The [tutorial](../master/tutorial) directory has many examples 16 | 17 | * [tutorial/example0.js](../master/tutorial/example0.js) - shows a demonstration of the redux-es5 store with a manual overall reducer 18 | * [tutorial/example1.js](../master/tutorial/example1.js) - shows the same thing but utilizes the redux-es5 combineReducers 19 | * [tutorial/example1-react.js](../master/tutorial/example1-react.js) - shows the view layer as expressed as React without JSX while still rendering via fully fledged React Components utilizing [hyperx](https://github.com/substack/hyperx) 20 | * [tutorial/example1-react-withoutClass.js](../master/tutorial/example1-react-withoutClass.js) - same thing as example1-react but utilizing the polyfill equivalent for es6 extends. 21 | * [tutorial/example2-react.js](../master/tutorial/example2-react.js) - Adds clicking on an item to mark it as completed. 22 | * [tutorial/example3-react.js](../master/tutorial/example3-react.js) - Adds a filter to show All, show active, and show completed. 23 | * [tutorial/example4-react.js](../master/tutorial/example4-react.js) - Refactor demonstrating nested classes and presentational components. 24 | * [tutorial/example5-react.js](../master/tutorial/example5-react.js) - Refactor demonstrating more separation of container and presentational components. 25 | * [tutorial/example6-react.js](../master/tutorial/example6-react.js) - Demonstrates the connect binding. Currently supports React Components, more on the way. 26 | 27 | You can open the corresponding html pages (e.g. [tutorial/index-example4.html](../master/tutorial/index-example4.html) )in the tutorial to see it in action. 28 | 29 | 30 | Example 31 | ======= 32 | *taken from [example/app.js](../master/example/app.js)* 33 | 34 | The [connect declaration](../master/example/components/store.js) is the link between redux-es5 storage that drives this view layer. 35 | 36 | var react = require('react') 37 | var reactdom = require('react-dom'); 38 | var hyperx = require('hyperx') 39 | var hx = hyperx(react.createElement) 40 | 41 | var connect = require('./components/store').connect 42 | var AddTodo = require('./components/AddTodo')(connect) 43 | var VisibleTodoList = require('./components/VisibleTodoList')(connect) 44 | var Footer = require('./components/Footer')(connect) 45 | 46 | var TodoApp = react.createClass({ 47 | render : function() { 48 | return hx`
49 | ${react.createElement(AddTodo)} 50 | ${react.createElement(VisibleTodoList)} 51 | Show ${' '} 52 | ${react.createElement(Footer)} 53 |
` 54 | } 55 | }); 56 | reactdom.render(react.createElement(TodoApp),document.querySelector('#content')) 57 | 58 | 59 | Coverage 60 | ======== 61 | 62 | 63 | STATUS 64 | ====== 65 | 66 | * createStore 67 | * combineReducers 68 | * connect 69 | 70 | 71 | I like JSX, I like Webpack, I like Babel, and I like ES6 72 | -------------------------------------------------------- 73 | 74 | Then this module is probably not for you! JSX, Webpack and Babel are really quite cool but there are some people 75 | who may not prefer this type of stack added onto thier Node development cycle. 76 | 77 | Why Do I want to use this? 78 | -------------------------- 79 | 80 | This module is really aimed at people who would like to use Redux and React but without introducing a transpiler, 81 | transpiler configurations, Webpack, and those people who may not want to use JSX or particularly care for ES6. 82 | 83 | If you like using Browserify and regular ES5 this module is for you! 84 | 85 | CONTRIB 86 | ======= 87 | 88 | Please! 89 | 90 | LICENSE 91 | ======= 92 | 93 | MIT License 94 | 95 | Copyright (c) [2016] [David Wee] 96 | 97 | Permission is hereby granted, free of charge, to any person obtaining a copy 98 | of this software and associated documentation files (the "Software"), to deal 99 | in the Software without restriction, including without limitation the rights 100 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 101 | copies of the Software, and to permit persons to whom the Software is 102 | furnished to do so, subject to the following conditions: 103 | 104 | The above copyright notice and this permission notice shall be included in all 105 | copies or substantial portions of the Software. 106 | 107 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 108 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 109 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 110 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 111 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 112 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 113 | SOFTWARE. 114 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | var react = require('react') 2 | var reactdom = require('react-dom'); 3 | var hyperx = require('hyperx') 4 | var hx = hyperx(react.createElement) 5 | 6 | var connect = require('./components/store').connect 7 | var AddTodo = require('./components/AddTodo')(connect) 8 | var VisibleTodoList = require('./components/VisibleTodoList')(connect) 9 | var Footer = require('./components/Footer')(connect) 10 | 11 | 12 | var TodoApp = react.createClass({ 13 | render : function() { 14 | return hx`
15 | ${react.createElement(AddTodo)} 16 | ${react.createElement(VisibleTodoList)} 17 | Show ${' '} 18 | ${react.createElement(Footer)} 19 |
` 20 | } 21 | }); 22 | reactdom.render(react.createElement(TodoApp),document.querySelector('#content')) 23 | -------------------------------------------------------------------------------- /example/components/AddTodo.js: -------------------------------------------------------------------------------- 1 | var react = require('react') 2 | var hyperx = require('hyperx') 3 | var hx = hyperx(react.createElement) 4 | 5 | var AddTodoComponent = function(connect) { 6 | var nextTodoId = 0; 7 | var myinput; 8 | var AddTodo = react.createClass({ 9 | render: function() { 10 | var that = this; 11 | return hx`
12 | 15 | 23 |
` 24 | } 25 | }) 26 | AddTodo = connect(null, null)(AddTodo); 27 | return AddTodo 28 | } 29 | module.exports = exports = AddTodoComponent; 30 | -------------------------------------------------------------------------------- /example/components/Footer.js: -------------------------------------------------------------------------------- 1 | var react = require('react') 2 | var hyperx = require('hyperx') 3 | var hx = hyperx(react.createElement) 4 | 5 | var FooterComponent = function(connect) { 6 | var Link = react.createClass({ 7 | render: function() { 8 | var that = this; 9 | if (this.props.active) { 10 | return hx`${this.props.children}` 11 | } 12 | return hx`${this.props.children}`; 16 | } 17 | }) 18 | var FilterLink = connect(function(state,ownProps) { 19 | return { 20 | active : (ownProps.filter === state.visibilityFilter), 21 | children : ownProps.children 22 | } 23 | },function(dispatch,ownProps) { 24 | return { 25 | onClick: function() { 26 | dispatch({ 27 | type:'SET_VISIBILITY_FILTER', 28 | filter:ownProps.filter 29 | }) 30 | } 31 | } 32 | })(Link) 33 | var Footer = react.createClass({ 34 | render: function() { 35 | return hx`
${react.createElement(FilterLink,{filter:'SHOW_ALL',children:'All'})} 36 | ${react.createElement(FilterLink,{filter:'SHOW_ACTIVE',children:'Active'})} 37 | ${react.createElement(FilterLink,{filter:'SHOW_COMPLETED',children:'Completed'})}
` 38 | } 39 | }) 40 | return Footer 41 | } 42 | module.exports = exports = FooterComponent; 43 | -------------------------------------------------------------------------------- /example/components/VisibleTodoList.js: -------------------------------------------------------------------------------- 1 | var react = require('react') 2 | var hyperx = require('hyperx') 3 | var hx = hyperx(react.createElement) 4 | 5 | var VisibleTodoListComponent = function(connect) { 6 | var getVisibleTodos = function(todos,filter) { 7 | switch (filter) { 8 | case 'SHOW_ALL' : 9 | return todos 10 | case 'SHOW_COMPLETED' : 11 | return todos.filter(function(t) { return t.completed }) 12 | case 'SHOW_ACTIVE' : 13 | return todos.filter(function(t) { return !t.completed }) 14 | default: 15 | break; 16 | } 17 | } 18 | var Todo = react.createClass({ 19 | render: function() { 20 | var that = this; 21 | return hx`
  • ${this.props.text}
  • ` 23 | } 24 | }) 25 | var TodoList = react.createClass({ 26 | render: function() { 27 | var that = this; 28 | return hx`` 39 | } 40 | }) 41 | var mapStateToProps = function(state) { 42 | return { 43 | todos: getVisibleTodos(state.todos,state.visibilityFilter) 44 | } 45 | } 46 | var mapDispatchToProps = function(dispatch) { 47 | return { 48 | onTodoClick: function(id) { 49 | dispatch({ 50 | type:'TOGGLE_TODO', 51 | id:id 52 | }) 53 | } 54 | } 55 | } 56 | var VisibleTodoList = connect(mapStateToProps,mapDispatchToProps)(TodoList) 57 | return VisibleTodoList 58 | } 59 | module.exports = exports = VisibleTodoListComponent; 60 | -------------------------------------------------------------------------------- /example/components/store.js: -------------------------------------------------------------------------------- 1 | var redux = require('../../') 2 | var createStore = redux.createStore; 3 | var todo = function(state,action) { 4 | switch (action.type) { 5 | case 'ADD_TODO' : 6 | return { 7 | id: action.id, 8 | text: action.text, 9 | completed:false 10 | } 11 | break; 12 | case 'TOGGLE_TODO' : 13 | if (state.id !== action.id) { 14 | return state 15 | } 16 | return { 17 | type: state.type, 18 | id : state.id, 19 | text: state.text, 20 | completed: !state.completed 21 | } 22 | break; 23 | default: 24 | return state 25 | break; 26 | } 27 | } 28 | var todos = function(state, action) { 29 | if (state === undefined) 30 | state = [] 31 | switch (action.type) { 32 | case 'ADD_TODO': 33 | return state.concat(todo(undefined,action)) 34 | break; 35 | case 'TOGGLE_TODO' : 36 | return state.map(function(t) { 37 | return todo(t,action) 38 | }) 39 | break; 40 | default: 41 | return state; 42 | } 43 | } 44 | 45 | var visibilityFilter = function(state, action) { 46 | if (state === undefined) 47 | state = 'SHOW_ALL' 48 | switch (action.type) { 49 | case 'SET_VISIBILITY_FILTER': 50 | return action.filter; 51 | break; 52 | default: 53 | return state 54 | } 55 | } 56 | 57 | var combineReducers = redux.combineReducers; 58 | var todoApp = combineReducers({ 59 | todos:todos, 60 | visibilityFilter:visibilityFilter 61 | }); 62 | var store = createStore(todoApp) 63 | var connect = redux.connect(store) 64 | exports.store = store; 65 | exports.connect = connect; 66 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports.createStore = require('./lib/createStore') 2 | exports.combineReducers = require('./lib/combineReducers') 3 | exports.connect = require('./lib/connect') 4 | exports.polyfill = require('./lib/polyfill') 5 | -------------------------------------------------------------------------------- /lib/combineReducers.js: -------------------------------------------------------------------------------- 1 | var combineReducers = function(reducers) { 2 | return function(state,action) { 3 | if (state == undefined) { 4 | state = {} 5 | } 6 | return Object.keys(reducers) 7 | .reduce(function(nextState,key) { 8 | nextState[key] = reducers[key](state[key],action) 9 | return nextState; 10 | },{}) 11 | } 12 | } 13 | module.exports = exports = combineReducers; 14 | -------------------------------------------------------------------------------- /lib/connect.js: -------------------------------------------------------------------------------- 1 | var react = require('react') 2 | var objectAssign = require('object-assign') 3 | var hyperx = require('hyperx') 4 | var hx = hyperx(react.createElement) 5 | var connect = function(store) { 6 | if (!store) { 7 | throw new Error("Store is undefined") 8 | } 9 | return function(mapStateToProps,mapDispatchToProps) { 10 | return function(component) { 11 | var hasSubscribed = false; 12 | return react.createClass({ 13 | componentDidMount:function() { 14 | var that = this; 15 | this.unsubscribe = store.subscribe(function() { 16 | that.forceUpdate() 17 | }) 18 | }, 19 | comonentWillUnmount:function() { 20 | this.unsubscribe(); 21 | }, 22 | render:function() { 23 | // this could be a candidate for optimization 24 | var state = store.getState(); 25 | var ownProps = this.props; 26 | var _props1 = {}; 27 | var _props2 = {}; 28 | if (mapStateToProps) 29 | _props1 = mapStateToProps(state,ownProps); 30 | if (mapDispatchToProps) 31 | _props2 = mapDispatchToProps(store.dispatch,ownProps); 32 | else 33 | _props2 = { dispatch : store.dispatch } 34 | var props = objectAssign(_props1,_props2) 35 | if ((mapStateToProps) && (hasSubscribed === false)) { 36 | store.subscribe(function() { 37 | var state = store.getState(); 38 | var _props1 = mapStateToProps(state,ownProps); 39 | props = objectAssign(_props1,_props2) 40 | }) 41 | hasSubscribed = true; 42 | } 43 | return hx`${react.createElement(component,props)}` 44 | } 45 | }) 46 | } 47 | } 48 | } 49 | module.exports = exports = connect; 50 | -------------------------------------------------------------------------------- /lib/createStore.js: -------------------------------------------------------------------------------- 1 | var combineReducers = function(reducers) { 2 | return function(state,action) { 3 | if (state == undefined) { 4 | state = {} 5 | } 6 | return Object.keys(reducers) 7 | .reduce(function(nextState,key) { 8 | nextState[key] = reducers[key](state[key],action) 9 | return nextState; 10 | },{}) 11 | } 12 | } 13 | exports.combineReducers = combineReducers; 14 | 15 | var createStore = function(reducer) { 16 | var state; 17 | var listeners = []; 18 | var getState = function () { 19 | return state 20 | } 21 | var dispatch = function(action) { 22 | //console.log('action:', action) 23 | state = reducer(state,action) 24 | //console.log("New state:", state) 25 | listeners.forEach(function(listener) { 26 | listener(); 27 | }) 28 | } 29 | var subscribe = function(listener) { 30 | listeners.push(listener) 31 | } 32 | dispatch({}) 33 | return {getState:getState,dispatch:dispatch,subscribe:subscribe} 34 | } 35 | module.exports = exports = createStore; 36 | -------------------------------------------------------------------------------- /lib/polyfill.js: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 2 | var object_assign = function (target) { 3 | if (target === undefined || target === null) { 4 | throw new TypeError('Cannot convert undefined or null to object'); 5 | } 6 | var output = Object(target); 7 | for (var index = 1; index < arguments.length; index++) { 8 | var source = arguments[index]; 9 | if (source !== undefined && source !== null) { 10 | for (var nextKey in source) { 11 | if (source.hasOwnProperty(nextKey)) { 12 | output[nextKey] = source[nextKey]; 13 | } 14 | } 15 | } 16 | } 17 | return output; 18 | }; 19 | 20 | exports.object = { 21 | assign : object_assign 22 | } 23 | exports.fill = function() { 24 | if (typeof Object.assign != 'function') { 25 | Object.assign = object_assign; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-es5", 3 | "author": "David Wee (http://rook2pawn.com)", 4 | "version": "1.1.3", 5 | "description": "redux es5", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "tape $(find test -name '*.js')" 9 | }, 10 | "keywords" : ["redux", "react", "es5", "hyperx", "jsx"], 11 | "license": "MIT", 12 | "devDependencies": { 13 | "deep-freeze": "0.0.1" 14 | }, 15 | "dependencies": { 16 | "hyperx": "^2.0.3", 17 | "object-assign": "^4.1.0", 18 | "react": "^15.0.2", 19 | "tape": "^4.5.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/test-combineReducers.js: -------------------------------------------------------------------------------- 1 | var combineReducers = require('../lib/combineReducers') 2 | var deepFreeze = require('deep-freeze') 3 | var test = require('tape') 4 | 5 | test('combine reducer gives default state', function(t) { 6 | t.plan(1); 7 | var reducer = function(state,action) { 8 | if (state === undefined) { 9 | state = [] 10 | } 11 | switch (action.type) { 12 | default: 13 | return state; 14 | break; 15 | } 16 | }; 17 | var reducer2 = function(state,action) { 18 | if (state === undefined) { 19 | state = 0 20 | } 21 | switch (action.type) { 22 | default: 23 | return state; 24 | break; 25 | } 26 | }; 27 | var app = combineReducers({ 28 | foo : reducer, 29 | bar : reducer2 30 | }); 31 | var stateBefore = {foo:undefined,bar:undefined}; 32 | var action = {}; 33 | var stateAfter = {foo:[],bar:0}; 34 | deepFreeze(stateBefore) 35 | deepFreeze(action) 36 | 37 | t.deepEquals(app(stateBefore, action),stateAfter) 38 | }) 39 | test('combine reducer follows a non default action', function(t) { 40 | t.plan(2); 41 | var reducer = function(state,action) { 42 | if (state === undefined) { 43 | state = [] 44 | } 45 | switch (action.type) { 46 | case 'ADD_ITEM' : 47 | return state.concat(action.item) 48 | break; 49 | case 'INCR_ITEM' : 50 | return state 51 | .slice(0,action.id) 52 | .concat([state[action.id]+1]) 53 | .concat(state.slice(action.id+1)) 54 | break; 55 | default: 56 | return state; 57 | break; 58 | } 59 | } 60 | var app = combineReducers({ 61 | foo : reducer 62 | }) 63 | 64 | var stateBefore = {foo:undefined}; 65 | var action = {type:'ADD_ITEM', item:4}; 66 | var stateAfter = {foo:[4]}; 67 | deepFreeze(stateBefore) 68 | deepFreeze(action) 69 | t.deepEquals(app(stateBefore,action), stateAfter); 70 | 71 | 72 | var stateBefore2 = {foo:[3,7,5,11,13]} 73 | var action2 = {type:'INCR_ITEM', id:3}; 74 | var stateAfter2 = {foo:[3,7,5,12,13]}; 75 | deepFreeze(stateBefore2) 76 | deepFreeze(action2) 77 | t.deepEquals(app(stateBefore2,action2), stateAfter2); 78 | }) 79 | -------------------------------------------------------------------------------- /test/test-connect.js: -------------------------------------------------------------------------------- 1 | var redux = require('../'); 2 | var test = require('tape'); 3 | 4 | 5 | test.skip('connect elementary test', function(t) { 6 | }) 7 | -------------------------------------------------------------------------------- /test/test-createStore.js: -------------------------------------------------------------------------------- 1 | var createStore = require('../lib/createStore'); 2 | var combineReducers = require('../lib/combineReducers'); 3 | var test = require('tape'); 4 | 5 | 6 | test('check that store defers default state to the reducer', function(t) { 7 | t.plan(1) 8 | var reducer = function(state,action) { 9 | if (state === undefined) { 10 | state = [] 11 | } 12 | switch (action.type) { 13 | default: 14 | return state; 15 | break; 16 | } 17 | } 18 | t.deepEquals(createStore(reducer).getState(),[]) 19 | }) 20 | 21 | 22 | test('getState - dispatch test', function(t) { 23 | t.plan(3) 24 | var reducer = function(state,action) { 25 | if (state === undefined) { 26 | state = [] 27 | } 28 | switch (action.type) { 29 | case 'ADD_ITEM' : 30 | return state.concat([action.val]) 31 | break; 32 | default: 33 | return state; 34 | break; 35 | } 36 | } 37 | var store = createStore(reducer); 38 | t.deepEquals(store.getState(),[]) 39 | store.dispatch({type:'ADD_ITEM', val:3}) 40 | t.deepEquals(store.getState(), [3]) 41 | store.dispatch({type:'ADD_ITEM', val:5}) 42 | t.deepEquals(store.getState(), [3,5]) 43 | }) 44 | 45 | 46 | 47 | 48 | test('getState - dispatch test with combineReducers', function(t) { 49 | var reducer = function(state,action) { 50 | if (state === undefined) { 51 | state = [] 52 | } 53 | switch (action.type) { 54 | case 'ADD_ITEM' : 55 | return state.concat([action.val]) 56 | break; 57 | default: 58 | return state; 59 | break; 60 | } 61 | } 62 | var reducer2 = function(state,action) { 63 | if (state === undefined) { 64 | state = 0 65 | } 66 | switch (action.type) { 67 | case 'INCR' : 68 | return state+1; 69 | break; 70 | case 'DOUBLE' : 71 | return state*2; 72 | break; 73 | default: 74 | return state; 75 | break; 76 | } 77 | } 78 | var store = createStore(combineReducers({list:reducer,number:reducer2})) 79 | t.deepEquals(store.getState(),{list:[],number:0}) 80 | store.dispatch({type:'ADD_ITEM', val:3}) 81 | store.dispatch({type:'ADD_ITEM', val:7}) 82 | store.dispatch({type:'INCR'}) 83 | store.dispatch({type:'INCR'}) 84 | store.dispatch({type:'DOUBLE'}) 85 | t.deepEquals(store.getState(),{list:[3,7],number:4}) 86 | t.end() 87 | }) 88 | -------------------------------------------------------------------------------- /tutorial/example0.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | 3 | var todo = function(state,action) { 4 | switch (action.type) { 5 | case 'ADD_TODO' : 6 | return { 7 | id: action.id, 8 | text: action.text, 9 | completed:false 10 | } 11 | break; 12 | case 'TOGGLE_TODO' : 13 | if (state.id !== action.id) { 14 | return state 15 | } 16 | return { 17 | type: state.type, 18 | id : state.id, 19 | text: state.text, 20 | completed: !state.completed 21 | } 22 | break; 23 | default: 24 | return state 25 | break; 26 | } 27 | } 28 | var todos = function(state, action) { 29 | if (state === undefined) 30 | state = [] 31 | switch (action.type) { 32 | case 'ADD_TODO': 33 | return state.concat(todo(undefined,action)) 34 | break; 35 | case 'TOGGLE_TODO' : 36 | return state.map(function(t) { 37 | return todo(t,action) 38 | }) 39 | break; 40 | default: 41 | return state; 42 | } 43 | } 44 | 45 | var visibilityFilter = function(state, action) { 46 | if (state === undefined) 47 | state = 'SHOW_ALL' 48 | switch (action.type) { 49 | case 'SET_VISIBILITY_FILTER': 50 | return action.filter; 51 | break; 52 | default: 53 | return state 54 | } 55 | } 56 | 57 | var todoApp = function(state, action) { 58 | if (state === undefined) 59 | state = {} 60 | return { 61 | todos: todos(state.todos,action), 62 | visibilityFilter: visibilityFilter(state.visibilityFilter,action) 63 | } 64 | } 65 | var createStore = redux.createStore; 66 | var store = createStore(todoApp) 67 | 68 | console.log('Initial state:'); 69 | console.log(store.getState()); 70 | console.log('---------------') 71 | 72 | console.log('Dispatching ADD_TODO'); 73 | store.dispatch({ 74 | type:'ADD_TODO', 75 | id: 0, 76 | text:'Learn Redux' 77 | }); 78 | console.log('Current state:'); 79 | console.log(store.getState()); 80 | console.log('---------------') 81 | 82 | 83 | 84 | console.log('Dispatching ADD_TODO'); 85 | store.dispatch({ 86 | type:'ADD_TODO', 87 | id: 1, 88 | text:'Go Shopping' 89 | }); 90 | console.log('Current state:'); 91 | console.log(store.getState()); 92 | console.log('---------------') 93 | 94 | 95 | 96 | console.log('Dispatching TOGGLE_TODO'); 97 | store.dispatch({ 98 | type:'TOGGLE_TODO', 99 | id: 0 100 | }); 101 | console.log('Current state:'); 102 | console.log(store.getState()); 103 | console.log('---------------') 104 | 105 | 106 | console.log('Dispatching SET_VISIBILITY_FILTER') 107 | store.dispatch({ 108 | type:'SET_VISIBILITY_FILTER', 109 | filter:'SHOW_COMPLETED' 110 | }); 111 | console.log('Current state:'); 112 | console.log(store.getState()); 113 | console.log('---------------') 114 | -------------------------------------------------------------------------------- /tutorial/example1-react-withoutClass.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | var react = require('react') 3 | var toString = require('react-dom/server').renderToString; 4 | var reactdom = require('react-dom'); 5 | var hyperx = require('hyperx') 6 | var hx = hyperx(react.createElement) 7 | 8 | var todo = function(state,action) { 9 | switch (action.type) { 10 | case 'ADD_TODO' : 11 | return { 12 | id: action.id, 13 | text: action.text, 14 | completed:false 15 | } 16 | break; 17 | case 'TOGGLE_TODO' : 18 | if (state.id !== action.id) { 19 | return state 20 | } 21 | return { 22 | type: state.type, 23 | id : state.id, 24 | text: state.text, 25 | completed: !state.completed 26 | } 27 | break; 28 | default: 29 | return state 30 | break; 31 | } 32 | } 33 | var todos = function(state, action) { 34 | if (state === undefined) 35 | state = [] 36 | switch (action.type) { 37 | case 'ADD_TODO': 38 | return state.concat(todo(undefined,action)) 39 | break; 40 | case 'TOGGLE_TODO' : 41 | return state.map(function(t) { 42 | return todo(t,action) 43 | }) 44 | break; 45 | default: 46 | return state; 47 | } 48 | } 49 | 50 | var visibilityFilter = function(state, action) { 51 | if (state === undefined) 52 | state = 'SHOW_ALL' 53 | switch (action.type) { 54 | case 'SET_VISIBILITY_FILTER': 55 | return action.filter; 56 | break; 57 | default: 58 | return state 59 | } 60 | } 61 | 62 | var combineReducers = redux.combineReducers; 63 | var todoApp = combineReducers({ 64 | todos:todos, 65 | visibilityFilter:visibilityFilter 66 | }); 67 | var createStore = redux.createStore; 68 | var store = createStore(todoApp) 69 | var Component = react.Component; 70 | var nextTodoId = 0; 71 | var myinput; 72 | 73 | 74 | var TodoApp = function() { 75 | Component.call(this); 76 | this.render = function() { 77 | return hx`
    78 | 81 | 89 |
    90 | 95 |
    ` 96 | } 97 | } 98 | TodoApp.prototype = Object.create(Component.prototype); 99 | TodoApp.prototype.constructor = Component; 100 | 101 | var Factory = react.createFactory(TodoApp) 102 | var render = function() { 103 | var root = Factory({todos:store.getState().todos}) 104 | reactdom.render(root, document.querySelector('#content')) 105 | } 106 | store.subscribe(render) 107 | render() 108 | -------------------------------------------------------------------------------- /tutorial/example1-react.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | var react = require('react') 3 | var toString = require('react-dom/server').renderToString; 4 | var reactdom = require('react-dom'); 5 | var hyperx = require('hyperx') 6 | var hx = hyperx(react.createElement) 7 | 8 | var todo = function(state,action) { 9 | switch (action.type) { 10 | case 'ADD_TODO' : 11 | return { 12 | id: action.id, 13 | text: action.text, 14 | completed:false 15 | } 16 | break; 17 | case 'TOGGLE_TODO' : 18 | if (state.id !== action.id) { 19 | return state 20 | } 21 | return { 22 | type: state.type, 23 | id : state.id, 24 | text: state.text, 25 | completed: !state.completed 26 | } 27 | break; 28 | default: 29 | return state 30 | break; 31 | } 32 | } 33 | var todos = function(state, action) { 34 | if (state === undefined) 35 | state = [] 36 | switch (action.type) { 37 | case 'ADD_TODO': 38 | return state.concat(todo(undefined,action)) 39 | break; 40 | case 'TOGGLE_TODO' : 41 | return state.map(function(t) { 42 | return todo(t,action) 43 | }) 44 | break; 45 | default: 46 | return state; 47 | } 48 | } 49 | 50 | var visibilityFilter = function(state, action) { 51 | if (state === undefined) 52 | state = 'SHOW_ALL' 53 | switch (action.type) { 54 | case 'SET_VISIBILITY_FILTER': 55 | return action.filter; 56 | break; 57 | default: 58 | return state 59 | } 60 | } 61 | 62 | var combineReducers = redux.combineReducers; 63 | var todoApp = combineReducers({ 64 | todos:todos, 65 | visibilityFilter:visibilityFilter 66 | }); 67 | var createStore = redux.createStore; 68 | var store = createStore(todoApp) 69 | var Component = react.Component; 70 | var nextTodoId = 0; 71 | var myinput; 72 | 73 | /* 74 | class TodoApp extends Component { 75 | render() { 76 | return hx`
    77 | 80 | 88 |
    89 | 94 |
    ` 95 | } 96 | } 97 | */ 98 | var Factory = react.createFactory(TodoApp) 99 | var render = function() { 100 | var root = Factory({todos:store.getState().todos}) 101 | reactdom.render(root, document.querySelector('#content')) 102 | } 103 | store.subscribe(render) 104 | render() 105 | -------------------------------------------------------------------------------- /tutorial/example1.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | 3 | var todo = function(state,action) { 4 | switch (action.type) { 5 | case 'ADD_TODO' : 6 | return { 7 | id: action.id, 8 | text: action.text, 9 | completed:false 10 | } 11 | break; 12 | case 'TOGGLE_TODO' : 13 | if (state.id !== action.id) { 14 | return state 15 | } 16 | return { 17 | type: state.type, 18 | id : state.id, 19 | text: state.text, 20 | completed: !state.completed 21 | } 22 | break; 23 | default: 24 | return state 25 | break; 26 | } 27 | } 28 | var todos = function(state, action) { 29 | if (state === undefined) 30 | state = [] 31 | switch (action.type) { 32 | case 'ADD_TODO': 33 | return state.concat(todo(undefined,action)) 34 | break; 35 | case 'TOGGLE_TODO' : 36 | return state.map(function(t) { 37 | return todo(t,action) 38 | }) 39 | break; 40 | default: 41 | return state; 42 | } 43 | } 44 | 45 | var visibilityFilter = function(state, action) { 46 | if (state === undefined) 47 | state = 'SHOW_ALL' 48 | switch (action.type) { 49 | case 'SET_VISIBILITY_FILTER': 50 | return action.filter; 51 | break; 52 | default: 53 | return state 54 | } 55 | } 56 | 57 | var combineReducers = redux.combineReducers; 58 | /* 59 | var todoApp = function(state, action) { 60 | if (state === undefined) 61 | state = {} 62 | return { 63 | todos: todos(state.todos,action), 64 | visibilityFilter: visibilityFilter(state.visibilityFilter,action) 65 | } 66 | } 67 | */ 68 | var todoApp = combineReducers({ 69 | todos:todos, 70 | visibilityFilter:visibilityFilter 71 | }); 72 | var createStore = redux.createStore; 73 | var store = createStore(todoApp) 74 | 75 | console.log('Initial state:'); 76 | console.log(store.getState()); 77 | console.log('---------------') 78 | 79 | console.log('Dispatching ADD_TODO'); 80 | store.dispatch({ 81 | type:'ADD_TODO', 82 | id: 0, 83 | text:'Learn Redux' 84 | }); 85 | console.log('Current state:'); 86 | console.log(store.getState()); 87 | console.log('---------------') 88 | 89 | 90 | 91 | console.log('Dispatching ADD_TODO'); 92 | store.dispatch({ 93 | type:'ADD_TODO', 94 | id: 1, 95 | text:'Go Shopping' 96 | }); 97 | console.log('Current state:'); 98 | console.log(store.getState()); 99 | console.log('---------------') 100 | 101 | 102 | 103 | console.log('Dispatching TOGGLE_TODO'); 104 | store.dispatch({ 105 | type:'TOGGLE_TODO', 106 | id: 0 107 | }); 108 | console.log('Current state:'); 109 | console.log(store.getState()); 110 | console.log('---------------') 111 | 112 | 113 | console.log('Dispatching SET_VISIBILITY_FILTER') 114 | store.dispatch({ 115 | type:'SET_VISIBILITY_FILTER', 116 | filter:'SHOW_COMPLETED' 117 | }); 118 | console.log('Current state:'); 119 | console.log(store.getState()); 120 | console.log('---------------') 121 | -------------------------------------------------------------------------------- /tutorial/example2-react.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | var react = require('react') 3 | var toString = require('react-dom/server').renderToString; 4 | var reactdom = require('react-dom'); 5 | var hyperx = require('hyperx') 6 | var hx = hyperx(react.createElement) 7 | 8 | var todo = function(state,action) { 9 | switch (action.type) { 10 | case 'ADD_TODO' : 11 | return { 12 | id: action.id, 13 | text: action.text, 14 | completed:false 15 | } 16 | break; 17 | case 'TOGGLE_TODO' : 18 | if (state.id !== action.id) { 19 | return state 20 | } 21 | return { 22 | type: state.type, 23 | id : state.id, 24 | text: state.text, 25 | completed: !state.completed 26 | } 27 | break; 28 | default: 29 | return state 30 | break; 31 | } 32 | } 33 | var todos = function(state, action) { 34 | if (state === undefined) 35 | state = [] 36 | switch (action.type) { 37 | case 'ADD_TODO': 38 | return state.concat(todo(undefined,action)) 39 | break; 40 | case 'TOGGLE_TODO' : 41 | return state.map(function(t) { 42 | return todo(t,action) 43 | }) 44 | break; 45 | default: 46 | return state; 47 | } 48 | } 49 | 50 | var visibilityFilter = function(state, action) { 51 | if (state === undefined) 52 | state = 'SHOW_ALL' 53 | switch (action.type) { 54 | case 'SET_VISIBILITY_FILTER': 55 | return action.filter; 56 | break; 57 | default: 58 | return state 59 | } 60 | } 61 | 62 | var combineReducers = redux.combineReducers; 63 | var todoApp = combineReducers({ 64 | todos:todos, 65 | visibilityFilter:visibilityFilter 66 | }); 67 | var createStore = redux.createStore; 68 | var store = createStore(todoApp) 69 | var Component = react.Component; 70 | var nextTodoId = 0; 71 | var myinput; 72 | 73 | 74 | var TodoApp = function() { 75 | Component.call(this); 76 | this.render = function() { 77 | return hx`
    78 | 81 | 89 |
    90 | 100 |
    ` 101 | } 102 | } 103 | TodoApp.prototype = Object.create(Component.prototype); 104 | TodoApp.prototype.constructor = Component; 105 | 106 | var Factory = react.createFactory(TodoApp) 107 | var render = function() { 108 | var root = Factory({todos:store.getState().todos}) 109 | reactdom.render(root, document.querySelector('#content')) 110 | } 111 | store.subscribe(render) 112 | render() 113 | -------------------------------------------------------------------------------- /tutorial/example3-react.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | var react = require('react') 3 | var toString = require('react-dom/server').renderToString; 4 | var reactdom = require('react-dom'); 5 | var hyperx = require('hyperx') 6 | var hx = hyperx(react.createElement) 7 | 8 | var todo = function(state,action) { 9 | switch (action.type) { 10 | case 'ADD_TODO' : 11 | return { 12 | id: action.id, 13 | text: action.text, 14 | completed:false 15 | } 16 | break; 17 | case 'TOGGLE_TODO' : 18 | if (state.id !== action.id) { 19 | return state 20 | } 21 | return { 22 | type: state.type, 23 | id : state.id, 24 | text: state.text, 25 | completed: !state.completed 26 | } 27 | break; 28 | default: 29 | return state 30 | break; 31 | } 32 | } 33 | var todos = function(state, action) { 34 | if (state === undefined) 35 | state = [] 36 | switch (action.type) { 37 | case 'ADD_TODO': 38 | return state.concat(todo(undefined,action)) 39 | break; 40 | case 'TOGGLE_TODO' : 41 | return state.map(function(t) { 42 | return todo(t,action) 43 | }) 44 | break; 45 | default: 46 | return state; 47 | } 48 | } 49 | 50 | var visibilityFilter = function(state, action) { 51 | if (state === undefined) 52 | state = 'SHOW_ALL' 53 | switch (action.type) { 54 | case 'SET_VISIBILITY_FILTER': 55 | return action.filter; 56 | break; 57 | default: 58 | return state 59 | } 60 | } 61 | 62 | var combineReducers = redux.combineReducers; 63 | var todoApp = combineReducers({ 64 | todos:todos, 65 | visibilityFilter:visibilityFilter 66 | }); 67 | var createStore = redux.createStore; 68 | var store = createStore(todoApp) 69 | 70 | var getVisibleTodos = function(todos,filter) { 71 | switch (filter) { 72 | case 'SHOW_ALL' : 73 | return todos 74 | case 'SHOW_COMPLETED' : 75 | return todos.filter(function(t) { return t.completed }) 76 | case 'SHOW_ACTIVE' : 77 | return todos.filter(function(t) { return !t.completed }) 78 | default: 79 | break; 80 | } 81 | } 82 | var FilterLink = react.createClass({ 83 | render: function() { 84 | var that = this; 85 | if (this.props.filter === this.props.currentFilter) { 86 | return hx`${this.props.children}` 87 | } 88 | return hx`${this.props.children}`; 94 | } 95 | }) 96 | 97 | var nextTodoId = 0; 98 | var myinput; 99 | var TodoApp = react.createClass({ 100 | render : function() { 101 | var visibleTodos = getVisibleTodos(this.props.todos,this.props.visibilityFilter); 102 | return hx`
    103 | 106 | 114 |
    115 | 125 | Show ${' '} 126 | ${react.createElement(FilterLink,{filter:'SHOW_ALL',children:'All',currentFilter:this.props.visibilityFilter})} 127 | ${react.createElement(FilterLink,{filter:'SHOW_ACTIVE',children:'Active',currentFilter:this.props.visibilityFilter})} 128 | ${react.createElement(FilterLink,{filter:'SHOW_COMPLETED',children:'Completed',currentFilter:this.props.visibilityFilter})} 129 |
    ` 130 | } 131 | }); 132 | 133 | var render = function() { 134 | reactdom.render(react.createElement(TodoApp, { 135 | todos:store.getState().todos, 136 | visibilityFilter:store.getState().visibilityFilter 137 | }),document.querySelector('#content')) 138 | } 139 | store.subscribe(render) 140 | render() 141 | -------------------------------------------------------------------------------- /tutorial/example4-react.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | var react = require('react') 3 | var toString = require('react-dom/server').renderToString; 4 | var reactdom = require('react-dom'); 5 | var hyperx = require('hyperx') 6 | var hx = hyperx(react.createElement) 7 | 8 | var nextTodoId = 0; 9 | var myinput; 10 | 11 | var todo = function(state,action) { 12 | switch (action.type) { 13 | case 'ADD_TODO' : 14 | return { 15 | id: action.id, 16 | text: action.text, 17 | completed:false 18 | } 19 | break; 20 | case 'TOGGLE_TODO' : 21 | if (state.id !== action.id) { 22 | return state 23 | } 24 | return { 25 | type: state.type, 26 | id : state.id, 27 | text: state.text, 28 | completed: !state.completed 29 | } 30 | break; 31 | default: 32 | return state 33 | break; 34 | } 35 | } 36 | var todos = function(state, action) { 37 | if (state === undefined) 38 | state = [] 39 | switch (action.type) { 40 | case 'ADD_TODO': 41 | return state.concat(todo(undefined,action)) 42 | break; 43 | case 'TOGGLE_TODO' : 44 | return state.map(function(t) { 45 | return todo(t,action) 46 | }) 47 | break; 48 | default: 49 | return state; 50 | } 51 | } 52 | 53 | var visibilityFilter = function(state, action) { 54 | if (state === undefined) 55 | state = 'SHOW_ALL' 56 | switch (action.type) { 57 | case 'SET_VISIBILITY_FILTER': 58 | return action.filter; 59 | break; 60 | default: 61 | return state 62 | } 63 | } 64 | 65 | var combineReducers = redux.combineReducers; 66 | var todoApp = combineReducers({ 67 | todos:todos, 68 | visibilityFilter:visibilityFilter 69 | }); 70 | var createStore = redux.createStore; 71 | var store = createStore(todoApp) 72 | 73 | var getVisibleTodos = function(todos,filter) { 74 | switch (filter) { 75 | case 'SHOW_ALL' : 76 | return todos 77 | case 'SHOW_COMPLETED' : 78 | return todos.filter(function(t) { return t.completed }) 79 | case 'SHOW_ACTIVE' : 80 | return todos.filter(function(t) { return !t.completed }) 81 | default: 82 | break; 83 | } 84 | } 85 | var FilterLink = react.createClass({ 86 | render: function() { 87 | var that = this; 88 | if (this.props.filter === this.props.currentFilter) { 89 | return hx`${this.props.children}` 90 | } 91 | return hx`${this.props.children}`; 95 | } 96 | }) 97 | 98 | 99 | var Todo = react.createClass({ 100 | render: function() { 101 | var that = this; 102 | return hx`
  • ${this.props.text}
  • ` 104 | } 105 | }) 106 | var TodoList = react.createClass({ 107 | render: function() { 108 | var that = this; 109 | return hx`` 120 | } 121 | }) 122 | 123 | var AddTodo = react.createClass({ 124 | render: function() { 125 | var that = this; 126 | return hx`
    127 | 130 | 133 |
    ` 134 | } 135 | }) 136 | var Footer = react.createClass({ 137 | render: function() { 138 | return hx`
    ${react.createElement(FilterLink,{filter:'SHOW_ALL',children:'All',currentFilter:this.props.visibilityFilter,onClick:this.props.onFilterClick})} 139 | ${react.createElement(FilterLink,{filter:'SHOW_ACTIVE',children:'Active',currentFilter:this.props.visibilityFilter,onClick:this.props.onFilterClick})} 140 | ${react.createElement(FilterLink,{filter:'SHOW_COMPLETED',children:'Completed',currentFilter:this.props.visibilityFilter,onClick:this.props.onFilterClick})}
    ` 141 | } 142 | }) 143 | 144 | var TodoApp = react.createClass({ 145 | render : function() { 146 | return hx`
    147 | ${react.createElement(AddTodo,{ 148 | onAddClick:function(text) { 149 | store.dispatch({ 150 | type:'ADD_TODO', 151 | id:nextTodoId++, 152 | text:text 153 | }) 154 | myinput.value=''; 155 | } 156 | })} 157 | ${react.createElement(TodoList,{ 158 | onTodoClick:function(id) { 159 | store.dispatch({ 160 | type:'TOGGLE_TODO', 161 | id: id 162 | }) 163 | }, 164 | todos:getVisibleTodos(this.props.todos,this.props.visibilityFilter) 165 | })} 166 | Show ${' '} 167 | ${react.createElement(Footer,{ 168 | onFilterClick: function(filter) { 169 | store.dispatch({ 170 | type:'SET_VISIBILITY_FILTER', 171 | filter:filter 172 | }) 173 | }, 174 | visibilityFilter:this.props.visibilityFilter})} 175 |
    ` 176 | } 177 | }); 178 | 179 | var render = function() { 180 | reactdom.render(react.createElement(TodoApp, { 181 | todos:store.getState().todos, 182 | visibilityFilter:store.getState().visibilityFilter 183 | }),document.querySelector('#content')) 184 | } 185 | store.subscribe(render) 186 | render() 187 | -------------------------------------------------------------------------------- /tutorial/example5-react.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | var react = require('react') 3 | var toString = require('react-dom/server').renderToString; 4 | var reactdom = require('react-dom'); 5 | var hyperx = require('hyperx') 6 | var hx = hyperx(react.createElement) 7 | 8 | var nextTodoId = 0; 9 | var myinput; 10 | 11 | var todo = function(state,action) { 12 | switch (action.type) { 13 | case 'ADD_TODO' : 14 | return { 15 | id: action.id, 16 | text: action.text, 17 | completed:false 18 | } 19 | break; 20 | case 'TOGGLE_TODO' : 21 | if (state.id !== action.id) { 22 | return state 23 | } 24 | return { 25 | type: state.type, 26 | id : state.id, 27 | text: state.text, 28 | completed: !state.completed 29 | } 30 | break; 31 | default: 32 | return state 33 | break; 34 | } 35 | } 36 | var todos = function(state, action) { 37 | if (state === undefined) 38 | state = [] 39 | switch (action.type) { 40 | case 'ADD_TODO': 41 | return state.concat(todo(undefined,action)) 42 | break; 43 | case 'TOGGLE_TODO' : 44 | return state.map(function(t) { 45 | return todo(t,action) 46 | }) 47 | break; 48 | default: 49 | return state; 50 | } 51 | } 52 | 53 | var visibilityFilter = function(state, action) { 54 | if (state === undefined) 55 | state = 'SHOW_ALL' 56 | switch (action.type) { 57 | case 'SET_VISIBILITY_FILTER': 58 | return action.filter; 59 | break; 60 | default: 61 | return state 62 | } 63 | } 64 | 65 | var combineReducers = redux.combineReducers; 66 | var todoApp = combineReducers({ 67 | todos:todos, 68 | visibilityFilter:visibilityFilter 69 | }); 70 | var createStore = redux.createStore; 71 | var store = createStore(todoApp) 72 | 73 | var getVisibleTodos = function(todos,filter) { 74 | switch (filter) { 75 | case 'SHOW_ALL' : 76 | return todos 77 | case 'SHOW_COMPLETED' : 78 | return todos.filter(function(t) { return t.completed }) 79 | case 'SHOW_ACTIVE' : 80 | return todos.filter(function(t) { return !t.completed }) 81 | default: 82 | break; 83 | } 84 | } 85 | var Link = react.createClass({ 86 | render: function() { 87 | var that = this; 88 | if (this.props.active) { 89 | return hx`${this.props.children}` 90 | } 91 | return hx`${this.props.children}`; 95 | } 96 | }) 97 | 98 | var FilterLink = react.createClass({ 99 | componentDidMount:function() { 100 | var that = this; 101 | this.unsubscribe = store.subscribe(function() { 102 | that.forceUpdate() 103 | }) 104 | }, 105 | comonentWillUnmount:function() { 106 | this.unsubscribe(); 107 | }, 108 | render: function() { 109 | var props = this.props; 110 | var state = store.getState(); 111 | return hx`${react.createElement(Link, { 112 | active:(props.filter===state.visibilityFilter), 113 | onClick:function() { 114 | store.dispatch({ 115 | type:'SET_VISIBILITY_FILTER', 116 | filter:props.filter 117 | }) 118 | }, 119 | children:props.children})}` 120 | } 121 | }) 122 | 123 | 124 | var Todo = react.createClass({ 125 | render: function() { 126 | var that = this; 127 | return hx`
  • ${this.props.text}
  • ` 129 | } 130 | }) 131 | var TodoList = react.createClass({ 132 | render: function() { 133 | var that = this; 134 | return hx`` 145 | } 146 | }) 147 | 148 | var AddTodo = react.createClass({ 149 | render: function() { 150 | var that = this; 151 | return hx`
    152 | 155 | 166 |
    ` 167 | } 168 | }) 169 | var Footer = react.createClass({ 170 | render: function() { 171 | return hx`
    ${react.createElement(FilterLink,{filter:'SHOW_ALL',children:'All'})} 172 | ${react.createElement(FilterLink,{filter:'SHOW_ACTIVE',children:'Active'})} 173 | ${react.createElement(FilterLink,{filter:'SHOW_COMPLETED',children:'Completed'})}
    ` 174 | } 175 | }) 176 | 177 | var VisibleTodoList = react.createClass({ 178 | componentDidMount:function() { 179 | var that = this; 180 | this.unsubscribe = store.subscribe(function() { 181 | that.forceUpdate() 182 | }) 183 | }, 184 | comonentWillUnmount:function() { 185 | this.unsubscribe(); 186 | }, 187 | render: function() { 188 | var props = this.props; 189 | var state = store.getState(); 190 | return hx`${react.createElement(TodoList,{ 191 | todos:getVisibleTodos(state.todos,state.visibilityFilter), 192 | onTodoClick:function(id) { 193 | store.dispatch({ 194 | type:'TOGGLE_TODO', 195 | id:id 196 | }) 197 | }})}` 198 | } 199 | }) 200 | 201 | var TodoApp = react.createClass({ 202 | render : function() { 203 | return hx`
    204 | ${react.createElement(AddTodo)} 205 | ${react.createElement(VisibleTodoList)} 206 | Show ${' '} 207 | ${react.createElement(Footer)} 208 |
    ` 209 | } 210 | }); 211 | 212 | reactdom.render(react.createElement(TodoApp),document.querySelector('#content')) 213 | -------------------------------------------------------------------------------- /tutorial/example6-react.js: -------------------------------------------------------------------------------- 1 | var redux = require('../') 2 | var react = require('react') 3 | var reactdom = require('react-dom'); 4 | var hyperx = require('hyperx') 5 | var hx = hyperx(react.createElement) 6 | var createStore = redux.createStore; 7 | 8 | var nextTodoId = 0; 9 | var myinput; 10 | 11 | var todo = function(state,action) { 12 | switch (action.type) { 13 | case 'ADD_TODO' : 14 | return { 15 | id: action.id, 16 | text: action.text, 17 | completed:false 18 | } 19 | break; 20 | case 'TOGGLE_TODO' : 21 | if (state.id !== action.id) { 22 | return state 23 | } 24 | return { 25 | type: state.type, 26 | id : state.id, 27 | text: state.text, 28 | completed: !state.completed 29 | } 30 | break; 31 | default: 32 | return state 33 | break; 34 | } 35 | } 36 | var todos = function(state, action) { 37 | if (state === undefined) 38 | state = [] 39 | switch (action.type) { 40 | case 'ADD_TODO': 41 | return state.concat(todo(undefined,action)) 42 | break; 43 | case 'TOGGLE_TODO' : 44 | return state.map(function(t) { 45 | return todo(t,action) 46 | }) 47 | break; 48 | default: 49 | return state; 50 | } 51 | } 52 | 53 | var visibilityFilter = function(state, action) { 54 | if (state === undefined) 55 | state = 'SHOW_ALL' 56 | switch (action.type) { 57 | case 'SET_VISIBILITY_FILTER': 58 | return action.filter; 59 | break; 60 | default: 61 | return state 62 | } 63 | } 64 | 65 | var combineReducers = redux.combineReducers; 66 | var todoApp = combineReducers({ 67 | todos:todos, 68 | visibilityFilter:visibilityFilter 69 | }); 70 | var store = createStore(todoApp) 71 | // end of model layer 72 | 73 | //view layer 74 | var connect = redux.connect(store); 75 | 76 | 77 | var AddTodo = react.createClass({ 78 | render: function() { 79 | var that = this; 80 | return hx`
    81 | 84 | 92 |
    ` 93 | } 94 | }) 95 | AddTodo = connect(null, null)(AddTodo); 96 | 97 | 98 | var getVisibleTodos = function(todos,filter) { 99 | switch (filter) { 100 | case 'SHOW_ALL' : 101 | return todos 102 | case 'SHOW_COMPLETED' : 103 | return todos.filter(function(t) { return t.completed }) 104 | case 'SHOW_ACTIVE' : 105 | return todos.filter(function(t) { return !t.completed }) 106 | default: 107 | break; 108 | } 109 | } 110 | var Todo = react.createClass({ 111 | render: function() { 112 | var that = this; 113 | return hx`
  • ${this.props.text}
  • ` 115 | } 116 | }) 117 | var TodoList = react.createClass({ 118 | render: function() { 119 | var that = this; 120 | return hx`` 131 | } 132 | }) 133 | var mapStateToProps = function(state) { 134 | return { 135 | todos: getVisibleTodos(state.todos,state.visibilityFilter) 136 | } 137 | } 138 | var mapDispatchToProps = function(dispatch) { 139 | return { 140 | onTodoClick: function(id) { 141 | dispatch({ 142 | type:'TOGGLE_TODO', 143 | id:id 144 | }) 145 | } 146 | } 147 | } 148 | var VisibleTodoList = connect(mapStateToProps,mapDispatchToProps)(TodoList) 149 | 150 | 151 | 152 | 153 | var Link = react.createClass({ 154 | render: function() { 155 | var that = this; 156 | if (this.props.active) { 157 | return hx`${this.props.children}` 158 | } 159 | return hx`${this.props.children}`; 163 | } 164 | }) 165 | var FilterLink = connect(function(state,ownProps) { 166 | return { 167 | active : (ownProps.filter === state.visibilityFilter), 168 | children : ownProps.children 169 | } 170 | },function(dispatch,ownProps) { 171 | return { 172 | onClick: function() { 173 | dispatch({ 174 | type:'SET_VISIBILITY_FILTER', 175 | filter:ownProps.filter 176 | }) 177 | } 178 | } 179 | })(Link) 180 | var Footer = react.createClass({ 181 | render: function() { 182 | return hx`
    ${react.createElement(FilterLink,{filter:'SHOW_ALL',children:'All'})} 183 | ${react.createElement(FilterLink,{filter:'SHOW_ACTIVE',children:'Active'})} 184 | ${react.createElement(FilterLink,{filter:'SHOW_COMPLETED',children:'Completed'})}
    ` 185 | } 186 | }) 187 | 188 | var TodoApp = react.createClass({ 189 | render : function() { 190 | return hx`
    191 | ${react.createElement(AddTodo)} 192 | ${react.createElement(VisibleTodoList)} 193 | Show ${' '} 194 | ${react.createElement(Footer)} 195 |
    ` 196 | } 197 | }); 198 | 199 | reactdom.render(react.createElement(TodoApp),document.querySelector('#content')) 200 | -------------------------------------------------------------------------------- /tutorial/index-example1-react-withoutClass.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tutorial/index-example2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tutorial/index-example3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tutorial/index-example4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tutorial/index-example5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tutorial/index-example6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
    7 | 8 | 9 | 10 | --------------------------------------------------------------------------------