├── .babelrc ├── .gitignore ├── README.md ├── dist ├── wechat-weapp-redux.js └── wechat-weapp-redux.min.js ├── package.json ├── src ├── Provider.js ├── connect.js ├── index.js ├── shallowEqual.js ├── utils │ └── Object.js ├── warning.js └── wrapActionCreators.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ], 5 | "plugins": ["transform-object-rest-spread", "transform-class-properties"] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # Bower 30 | bower_components/ 31 | 32 | # idea 33 | .idea 34 | 35 | # do not keep dist 36 | #dist 37 | .DS_Store 38 | 39 | lib -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 微信小程序Redux绑定 3 | ============== 4 | 用于在微信小程序为页面绑定Redux Store。 5 | 6 | _PS: 代码是基于[react-redux](https://github.com/reactjs/react-redux)修改的_ 7 | 8 | ## 安装 9 | 1. clone或者下载代码库到本地: 10 | 11 | ```shell 12 | git clone https://github.com/charleyw/wechat-weapp-redux 13 | ``` 14 | 2. 将`dist/wechat-weapp-redux.js`(或者拷贝minify的也可以)文件直接拷贝到小程序的工程中,例如(下面假设我们把第三方包都安装在libs目录下): 15 | 16 | ``` shell 17 | cd wechat-weapp-redux 18 | cp -r dist/wechat-weapp-redux.js <小程序根目录>/libs 19 | ``` 20 | 上面的命令将包拷贝到小程序的`libs`目录下 21 | 22 | ## 使用 23 | 1. 将Redux Store绑定到App上。 24 | 25 | ```js 26 | const store = createStore(reducer) // redux store 27 | 28 | const WeAppRedux = require('./libs/wechat-weapp-redux/index.js'); 29 | const {Provider} = WeAppRedux; 30 | 31 | ``` 32 | **Provider**是用来把Redux的store绑定到App上。 33 | 34 | ``` 35 | App(Provider(store)({ 36 | onLaunch: function () { 37 | console.log("onLaunch") 38 | } 39 | })) 40 | ``` 41 | provider的实现只是简单的将store加到App这个global对象上,方便在页面中用getApp取出来 42 | 43 | 上面这段代码等同于: 44 | ``` 45 | App({ 46 | onLaunch: function() { 47 | console.log( "onLaunch" ) 48 | }, 49 | store: store 50 | }) 51 | ``` 52 | 2. 在页面的定义上使用connect,绑定redux store到页面上。 53 | 54 | ```js 55 | const pageConfig = { 56 | data: { 57 | }, 58 | ... 59 | } 60 | 61 | ``` 62 | 页面的定义 63 | 64 | ```js 65 | const mapStateToData = state => ({ 66 | todos: state.todos, 67 | visibilityFilter: state.visibilityFilter 68 | }) 69 | ``` 70 | 定义要映射哪些state到页面 71 | 72 | ```js 73 | const mapDispatchToPage = dispatch => ({ 74 | setVisibilityFilter: filter => dispatch(setVisibilityFilter(filter)), 75 | toggleTodo: id => dispatch(toggleTodo(id)), 76 | addTodo: text => dispatch(addTodo(text)), 77 | }) 78 | ``` 79 | 定义要映射哪些方法到页面 80 | 81 | ```js 82 | const nextPageConfig = connect(mapStateToData, mapDispatchToPage)(pageConfig) 83 | ``` 84 | 使用connect将上述定义添加到pageConfig中。 85 | 86 | ```js 87 | Page(nextPageConfig); 88 | ``` 89 | 注册小程序的页面 90 | 91 | 3. 说明 92 | 93 | 完成上述两步之后,你就可以在`this.data`中访问你在`mapStateToData`定义的数据了。 94 | 95 | `mapDispatchToPage`定义的action会被映射到`this`对象上。 96 | 97 | ## Example 98 | 99 | 详细的使用例子可以参照: [wechat-weapp-redux-todos](https://github.com/charleyw/wechat-weapp-redux-todos) 100 | 101 | 真机实测版请clone下面这个repo,用小程序开发工具开启预览: 102 | ``` 103 | git clone -b release https://github.com/charleyw/wechat-weapp-redux-todos.git 104 | ``` 105 | ​ 106 | -------------------------------------------------------------------------------- /dist/wechat-weapp-redux.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["WeAppRedux"] = factory(); 8 | else 9 | root["WeAppRedux"] = factory(); 10 | })(this, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) 20 | /******/ return installedModules[moduleId].exports; 21 | 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ exports: {}, 25 | /******/ id: moduleId, 26 | /******/ loaded: false 27 | /******/ }; 28 | 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | 32 | /******/ // Flag the module as loaded 33 | /******/ module.loaded = true; 34 | 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | 39 | 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | 46 | /******/ // __webpack_public_path__ 47 | /******/ __webpack_require__.p = ""; 48 | 49 | /******/ // Load entry module and return exports 50 | /******/ return __webpack_require__(0); 51 | /******/ }) 52 | /************************************************************************/ 53 | /******/ ([ 54 | /* 0 */ 55 | /***/ function(module, exports, __webpack_require__) { 56 | 57 | 'use strict'; 58 | 59 | var _Provider = __webpack_require__(3); 60 | 61 | var _Provider2 = _interopRequireDefault(_Provider); 62 | 63 | var _connect = __webpack_require__(4); 64 | 65 | var _connect2 = _interopRequireDefault(_connect); 66 | 67 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 68 | 69 | module.exports = { 70 | Provider: _Provider2.default, 71 | connect: _connect2.default 72 | }; 73 | 74 | /***/ }, 75 | /* 1 */ 76 | /***/ function(module, exports) { 77 | 78 | 'use strict'; 79 | 80 | var assign = function assign(target) { 81 | 'use strict'; 82 | // We must check against these specific cases. 83 | 84 | if (target === undefined || target === null) { 85 | throw new TypeError('Cannot convert undefined or null to object'); 86 | } 87 | 88 | var output = Object(target); 89 | for (var index = 1; index < arguments.length; index++) { 90 | var source = arguments[index]; 91 | if (source !== undefined && source !== null) { 92 | for (var nextKey in source) { 93 | if (source.hasOwnProperty(nextKey)) { 94 | output[nextKey] = source[nextKey]; 95 | } 96 | } 97 | } 98 | } 99 | return output; 100 | }; 101 | 102 | module.exports = { 103 | assign: assign 104 | }; 105 | 106 | /***/ }, 107 | /* 2 */ 108 | /***/ function(module, exports) { 109 | 110 | 'use strict'; 111 | 112 | /** 113 | * Prints a warning in the console if it exists. 114 | * 115 | * @param {String} message The warning message. 116 | * @returns {void} 117 | */ 118 | function warning(message) { 119 | /* eslint-disable no-console */ 120 | if (typeof console !== 'undefined' && typeof console.error === 'function') { 121 | console.error(message); 122 | } 123 | /* eslint-enable no-console */ 124 | try { 125 | // This error was thrown as a convenience so that if you enable 126 | // "break on all exceptions" in your console, 127 | // it would pause the execution at this line. 128 | throw new Error(message); 129 | /* eslint-disable no-empty */ 130 | } catch (e) {} 131 | /* eslint-enable no-empty */ 132 | } 133 | 134 | module.exports = warning; 135 | 136 | /***/ }, 137 | /* 3 */ 138 | /***/ function(module, exports, __webpack_require__) { 139 | 140 | 'use strict'; 141 | 142 | var _warning = __webpack_require__(2); 143 | 144 | var _warning2 = _interopRequireDefault(_warning); 145 | 146 | var _Object = __webpack_require__(1); 147 | 148 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 149 | 150 | function checkStoreShape(store) { 151 | var missingMethods = ['subscribe', 'dispatch', 'getState'].filter(function (m) { 152 | return !store.hasOwnProperty(m); 153 | }); 154 | 155 | if (missingMethods.length > 0) { 156 | (0, _warning2.default)('Store似乎不是一个合法的Redux Store对象: ' + '缺少这些方法: ' + missingMethods.join(', ') + '。'); 157 | } 158 | } 159 | 160 | function Provider(store) { 161 | checkStoreShape(store); 162 | return function (appConfig) { 163 | return (0, _Object.assign)({}, appConfig, { store: store }); 164 | }; 165 | } 166 | 167 | module.exports = Provider; 168 | 169 | /***/ }, 170 | /* 4 */ 171 | /***/ function(module, exports, __webpack_require__) { 172 | 173 | 'use strict'; 174 | 175 | var _shallowEqual = __webpack_require__(5); 176 | 177 | var _shallowEqual2 = _interopRequireDefault(_shallowEqual); 178 | 179 | var _warning = __webpack_require__(2); 180 | 181 | var _warning2 = _interopRequireDefault(_warning); 182 | 183 | var _wrapActionCreators = __webpack_require__(6); 184 | 185 | var _wrapActionCreators2 = _interopRequireDefault(_wrapActionCreators); 186 | 187 | var _Object = __webpack_require__(1); 188 | 189 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 190 | 191 | var defaultMapStateToProps = function defaultMapStateToProps(state) { 192 | return {}; 193 | }; // eslint-disable-line no-unused-vars 194 | var defaultMapDispatchToProps = function defaultMapDispatchToProps(dispatch) { 195 | return { dispatch: dispatch }; 196 | }; 197 | 198 | function connect(mapStateToProps, mapDispatchToProps) { 199 | var shouldSubscribe = Boolean(mapStateToProps); 200 | var mapState = mapStateToProps || defaultMapStateToProps; 201 | var app = getApp(); 202 | 203 | var mapDispatch = void 0; 204 | if (typeof mapDispatchToProps === 'function') { 205 | mapDispatch = mapDispatchToProps; 206 | } else if (!mapDispatchToProps) { 207 | mapDispatch = defaultMapDispatchToProps; 208 | } else { 209 | mapDispatch = (0, _wrapActionCreators2.default)(mapDispatchToProps); 210 | } 211 | 212 | return function wrapWithConnect(pageConfig) { 213 | 214 | function handleChange(options) { 215 | if (!this.unsubscribe) { 216 | return; 217 | } 218 | 219 | var state = this.store.getState(); 220 | var mappedState = mapState(state, options); 221 | if (!this.data || (0, _shallowEqual2.default)(this.data, mappedState)) { 222 | return; 223 | } 224 | this.setData(mappedState); 225 | } 226 | 227 | var _onLoad = pageConfig.onLoad, 228 | _onUnload = pageConfig.onUnload; 229 | 230 | 231 | function onLoad(options) { 232 | this.store = app.store; 233 | if (!this.store) { 234 | (0, _warning2.default)("Store对象不存在!"); 235 | } 236 | if (shouldSubscribe) { 237 | this.unsubscribe = this.store.subscribe(handleChange.bind(this, options)); 238 | handleChange.call(this, options); 239 | } 240 | if (typeof _onLoad === 'function') { 241 | _onLoad.call(this, options); 242 | } 243 | } 244 | 245 | function onUnload() { 246 | if (typeof _onUnload === 'function') { 247 | _onUnload.call(this); 248 | } 249 | typeof this.unsubscribe === 'function' && this.unsubscribe(); 250 | } 251 | 252 | return (0, _Object.assign)({}, pageConfig, mapDispatch(app.store.dispatch), { onLoad: onLoad, onUnload: onUnload }); 253 | }; 254 | } 255 | 256 | module.exports = connect; 257 | 258 | /***/ }, 259 | /* 5 */ 260 | /***/ function(module, exports) { 261 | 262 | "use strict"; 263 | 264 | function shallowEqual(objA, objB) { 265 | if (objA === objB) { 266 | return true; 267 | } 268 | 269 | var keysA = Object.keys(objA); 270 | var keysB = Object.keys(objB); 271 | 272 | if (keysA.length !== keysB.length) { 273 | return false; 274 | } 275 | 276 | // Test for A's keys different from B. 277 | var hasOwn = Object.prototype.hasOwnProperty; 278 | for (var i = 0; i < keysA.length; i++) { 279 | if (!hasOwn.call(objB, keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { 280 | return false; 281 | } 282 | } 283 | 284 | return true; 285 | } 286 | 287 | module.exports = shallowEqual; 288 | 289 | /***/ }, 290 | /* 6 */ 291 | /***/ function(module, exports) { 292 | 293 | 'use strict'; 294 | 295 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 296 | 297 | function bindActionCreator(actionCreator, dispatch) { 298 | return function () { 299 | return dispatch(actionCreator.apply(undefined, arguments)); 300 | }; 301 | } 302 | 303 | function bindActionCreators(actionCreators, dispatch) { 304 | if (typeof actionCreators === 'function') { 305 | return bindActionCreator(actionCreators, dispatch); 306 | } 307 | 308 | if ((typeof actionCreators === 'undefined' ? 'undefined' : _typeof(actionCreators)) !== 'object' || actionCreators === null) { 309 | throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators === 'undefined' ? 'undefined' : _typeof(actionCreators)) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?'); 310 | } 311 | 312 | var keys = Object.keys(actionCreators); 313 | var boundActionCreators = {}; 314 | for (var i = 0; i < keys.length; i++) { 315 | var key = keys[i]; 316 | var actionCreator = actionCreators[key]; 317 | if (typeof actionCreator === 'function') { 318 | boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); 319 | } 320 | } 321 | return boundActionCreators; 322 | } 323 | 324 | function wrapActionCreators(actionCreators) { 325 | return function (dispatch) { 326 | return bindActionCreators(actionCreators, dispatch); 327 | }; 328 | } 329 | 330 | module.exports = wrapActionCreators; 331 | 332 | /***/ } 333 | /******/ ]) 334 | }); 335 | ; -------------------------------------------------------------------------------- /dist/wechat-weapp-redux.min.js: -------------------------------------------------------------------------------- 1 | !function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.WeAppRedux=n():t.WeAppRedux=n()}(this,function(){return function(t){function n(o){if(e[o])return e[o].exports;var r=e[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,n),r.loaded=!0,r.exports}var e={};return n.m=t,n.c=e,n.p="",n(0)}([function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}var r=e(3),i=o(r),u=e(4),f=o(u);t.exports={Provider:i.default,connect:f.default}},function(t,n){"use strict";var e=function(t){if(void 0===t||null===t)throw new TypeError("Cannot convert undefined or null to object");for(var n=Object(t),e=1;arguments.length>e;e++){var o=arguments[e];if(void 0!==o&&null!==o)for(var r in o)o.hasOwnProperty(r)&&(n[r]=o[r])}return n};t.exports={assign:e}},function(t,n){"use strict";function e(t){"undefined"!=typeof console&&"function"==typeof console.error&&console.error(t);try{throw Error(t)}catch(t){}}t.exports=e},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}function r(t){var n=["subscribe","dispatch","getState"].filter(function(n){return!t.hasOwnProperty(n)});n.length>0&&(0,f.default)("Store似乎不是一个合法的Redux Store对象: 缺少这些方法: "+n.join(", ")+"。")}function i(t){return r(t),function(n){return(0,s.assign)({},n,{store:t})}}var u=e(2),f=o(u),s=e(1);t.exports=i},function(t,n,e){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}function r(t,n){var e=!!t,o=t||d,r=getApp(),i=void 0;return i="function"==typeof n?n:n?(0,a.default)(n):p,function(t){function n(t){if(this.unsubscribe){var n=this.store.getState(),e=o(n,t);this.data&&!(0,u.default)(this.data,e)&&this.setData(e)}}function f(t){this.store=r.store,this.store||(0,s.default)("Store对象不存在!"),e&&(this.unsubscribe=this.store.subscribe(n.bind(this,t)),n.call(this,t)),"function"==typeof a&&a.call(this,t)}function c(){"function"==typeof d&&d.call(this),"function"==typeof this.unsubscribe&&this.unsubscribe()}var a=t.onLoad,d=t.onUnload;return(0,l.assign)({},t,i(r.store.dispatch),{onLoad:f,onUnload:c})}}var i=e(5),u=o(i),f=e(2),s=o(f),c=e(6),a=o(c),l=e(1),d=function(t){return{}},p=function(t){return{dispatch:t}};t.exports=r},function(t,n){"use strict";function e(t,n){if(t===n)return!0;var e=Object.keys(t),o=Object.keys(n);if(e.length!==o.length)return!1;for(var r=Object.prototype.hasOwnProperty,i=0;e.length>i;i++)if(!r.call(n,e[i])||t[e[i]]!==n[e[i]])return!1;return!0}t.exports=e},function(t,n){"use strict";function e(t,n){return function(){return n(t.apply(void 0,arguments))}}function o(t,n){if("function"==typeof t)return e(t,n);if("object"!==(void 0===t?"undefined":i(t))||null===t)throw Error("bindActionCreators expected an object or a function, instead received "+(null===t?"null":void 0===t?"undefined":i(t))+'. Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?');for(var o=Object.keys(t),r={},u=0;o.length>u;u++){var f=o[u],s=t[f];"function"==typeof s&&(r[f]=e(s,n))}return r}function r(t){return function(n){return o(t,n)}}var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};t.exports=r}])}); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wechat-weapp-redux", 3 | "version": "0.1.3", 4 | "description": "Wechat weapp redux bindings", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "clean": "rimraf lib", 8 | "build:lib": "babel src --out-dir lib", 9 | "build:umd": "NODE_ENV=development webpack src/index.js dist/wechat-weapp-redux.js", 10 | "build:umd:min": "NODE_ENV=production webpack src/index.js dist/wechat-weapp-redux.min.js", 11 | "build": "npm run build:lib && npm run build:umd && npm run build:umd:min", 12 | "test": "echo \"Error: no test specified\" && exit 1", 13 | "prepublish": "npm run clean && npm run build" 14 | }, 15 | "author": "", 16 | "license": "MIT", 17 | "files": [ 18 | "dist", 19 | "lib", 20 | "src" 21 | ], 22 | "devDependencies": { 23 | "babel-cli": "^6.16.0", 24 | "babel-core": "^6.16.0", 25 | "babel-loader": "^6.2.5", 26 | "babel-plugin-transform-class-properties": "^6.16.0", 27 | "babel-plugin-transform-object-rest-spread": "^6.16.0", 28 | "babel-preset-es2015": "^6.16.0", 29 | "rimraf": "^2.5.4", 30 | "webpack": "^1.13.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Provider.js: -------------------------------------------------------------------------------- 1 | import warning from './warning.js' 2 | import {assign} from './utils/Object.js' 3 | 4 | function checkStoreShape(store) { 5 | const missingMethods = ['subscribe', 'dispatch', 'getState'].filter(m => !store.hasOwnProperty(m)); 6 | 7 | if(missingMethods.length > 0) { 8 | warning( 9 | 'Store似乎不是一个合法的Redux Store对象: ' + 10 | '缺少这些方法: ' + missingMethods.join(', ') + '。' 11 | ) 12 | } 13 | } 14 | 15 | function Provider(store) { 16 | checkStoreShape(store) 17 | return function(appConfig) { 18 | return assign({}, appConfig, {store}) 19 | } 20 | } 21 | 22 | module.exports = Provider -------------------------------------------------------------------------------- /src/connect.js: -------------------------------------------------------------------------------- 1 | import shallowEqual from './shallowEqual.js' 2 | import warning from './warning.js' 3 | import wrapActionCreators from './wrapActionCreators.js' 4 | import {assign} from './utils/Object.js' 5 | 6 | const defaultMapStateToProps = state => ({}) // eslint-disable-line no-unused-vars 7 | const defaultMapDispatchToProps = dispatch => ({dispatch}) 8 | 9 | function connect(mapStateToProps, mapDispatchToProps) { 10 | const shouldSubscribe = Boolean(mapStateToProps) 11 | const mapState = mapStateToProps || defaultMapStateToProps 12 | const app = getApp(); 13 | 14 | let mapDispatch 15 | if (typeof mapDispatchToProps === 'function') { 16 | mapDispatch = mapDispatchToProps 17 | } else if (!mapDispatchToProps) { 18 | mapDispatch = defaultMapDispatchToProps 19 | } else { 20 | mapDispatch = wrapActionCreators(mapDispatchToProps) 21 | } 22 | 23 | return function wrapWithConnect(pageConfig) { 24 | 25 | function handleChange(options) { 26 | if (!this.unsubscribe) { 27 | return 28 | } 29 | 30 | const state = this.store.getState() 31 | const mappedState = mapState(state, options); 32 | if (!this.data || shallowEqual(this.data, mappedState)) { 33 | return; 34 | } 35 | this.setData(mappedState) 36 | } 37 | 38 | const { 39 | onLoad: _onLoad, 40 | onUnload: _onUnload, 41 | } = pageConfig 42 | 43 | function onLoad(options) { 44 | this.store = app.store; 45 | if (!this.store) { 46 | warning("Store对象不存在!") 47 | } 48 | if(shouldSubscribe){ 49 | this.unsubscribe = this.store.subscribe(handleChange.bind(this, options)); 50 | handleChange.call(this, options) 51 | } 52 | if (typeof _onLoad === 'function') { 53 | _onLoad.call(this, options) 54 | } 55 | } 56 | 57 | function onUnload() { 58 | if (typeof _onUnload === 'function') { 59 | _onUnload.call(this) 60 | } 61 | typeof this.unsubscribe === 'function' && this.unsubscribe() 62 | } 63 | 64 | return assign({}, pageConfig, mapDispatch(app.store.dispatch), {onLoad, onUnload}) 65 | } 66 | } 67 | 68 | module.exports = connect -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Provider from './Provider.js' 2 | import connect from './connect.js' 3 | 4 | module.exports = { 5 | Provider: Provider, 6 | connect: connect 7 | } -------------------------------------------------------------------------------- /src/shallowEqual.js: -------------------------------------------------------------------------------- 1 | function shallowEqual(objA, objB) { 2 | if (objA === objB) { 3 | return true 4 | } 5 | 6 | const keysA = Object.keys(objA) 7 | const keysB = Object.keys(objB) 8 | 9 | if (keysA.length !== keysB.length) { 10 | return false 11 | } 12 | 13 | // Test for A's keys different from B. 14 | const hasOwn = Object.prototype.hasOwnProperty 15 | for (let i = 0; i < keysA.length; i++) { 16 | if (!hasOwn.call(objB, keysA[i]) || 17 | objA[keysA[i]] !== objB[keysA[i]]) { 18 | return false 19 | } 20 | } 21 | 22 | return true 23 | } 24 | 25 | module.exports = shallowEqual -------------------------------------------------------------------------------- /src/utils/Object.js: -------------------------------------------------------------------------------- 1 | const assign = function (target) { 2 | 'use strict'; 3 | // We must check against these specific cases. 4 | if (target === undefined || target === null) { 5 | throw new TypeError('Cannot convert undefined or null to object'); 6 | } 7 | 8 | var output = Object(target); 9 | for (var index = 1; index < arguments.length; index++) { 10 | var source = arguments[index]; 11 | if (source !== undefined && source !== null) { 12 | for (var nextKey in source) { 13 | if (source.hasOwnProperty(nextKey)) { 14 | output[nextKey] = source[nextKey]; 15 | } 16 | } 17 | } 18 | } 19 | return output; 20 | }; 21 | 22 | module.exports = { 23 | assign: assign 24 | } -------------------------------------------------------------------------------- /src/warning.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Prints a warning in the console if it exists. 3 | * 4 | * @param {String} message The warning message. 5 | * @returns {void} 6 | */ 7 | function warning(message) { 8 | /* eslint-disable no-console */ 9 | if (typeof console !== 'undefined' && typeof console.error === 'function') { 10 | console.error(message) 11 | } 12 | /* eslint-enable no-console */ 13 | try { 14 | // This error was thrown as a convenience so that if you enable 15 | // "break on all exceptions" in your console, 16 | // it would pause the execution at this line. 17 | throw new Error(message) 18 | /* eslint-disable no-empty */ 19 | } catch (e) {} 20 | /* eslint-enable no-empty */ 21 | } 22 | 23 | module.exports = warning -------------------------------------------------------------------------------- /src/wrapActionCreators.js: -------------------------------------------------------------------------------- 1 | function bindActionCreator(actionCreator, dispatch) { 2 | return function () { 3 | return dispatch(actionCreator.apply(undefined, arguments)); 4 | }; 5 | } 6 | 7 | function bindActionCreators(actionCreators, dispatch) { 8 | if (typeof actionCreators === 'function') { 9 | return bindActionCreator(actionCreators, dispatch); 10 | } 11 | 12 | if (typeof actionCreators !== 'object' || actionCreators === null) { 13 | throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?'); 14 | } 15 | 16 | var keys = Object.keys(actionCreators); 17 | var boundActionCreators = {}; 18 | for (var i = 0; i < keys.length; i++) { 19 | var key = keys[i]; 20 | var actionCreator = actionCreators[key]; 21 | if (typeof actionCreator === 'function') { 22 | boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); 23 | } 24 | } 25 | return boundActionCreators; 26 | } 27 | 28 | function wrapActionCreators(actionCreators) { 29 | return dispatch => bindActionCreators(actionCreators, dispatch) 30 | } 31 | 32 | module.exports = wrapActionCreators -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var webpack = require('webpack') 4 | var env = process.env.NODE_ENV 5 | 6 | var config = { 7 | module: { 8 | loaders: [ 9 | { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ } 10 | ] 11 | }, 12 | output: { 13 | library: 'WeAppRedux', 14 | libraryTarget: 'umd' 15 | }, 16 | plugins: [ 17 | new webpack.optimize.OccurenceOrderPlugin(), 18 | new webpack.DefinePlugin({ 19 | 'process.env.NODE_ENV': JSON.stringify(env) 20 | }) 21 | ] 22 | } 23 | 24 | if (env === 'production') { 25 | config.plugins.push( 26 | new webpack.optimize.UglifyJsPlugin({ 27 | compressor: { 28 | pure_getters: true, 29 | unsafe: true, 30 | unsafe_comps: true, 31 | screw_ie8: true, 32 | warnings: false 33 | } 34 | }) 35 | ) 36 | } 37 | 38 | module.exports = config 39 | --------------------------------------------------------------------------------