微信小程序集成Redux

IngridBallo 7年前
   <h2><strong>示例</strong></h2>    <p>先展示成果</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d53fa4bd689e7b175cae0a5d8072cd0c.gif"></p>    <h2><strong>Redux是什么</strong></h2>    <p>Redux 是 JavaScript 状态容器,提供可预测化的状态管理。</p>    <h2><strong>为什么要使用Redux</strong></h2>    <p>小程序俨然是一个类似Hybrid App的东西,前面是SPA,小程序提供一些原生功能的接口。</p>    <p>现在前端程序规模都比较大,页面状态,数据缓存,需要管理的东西太多。引入Redux可以方便的管理这些状态。并且Redux丰富的周边工具也是很有吸引力的。</p>    <h2><strong>集成Redux</strong></h2>    <h3><strong>小程序的模块化</strong></h3>    <p>微信的文档并没有指出如何使用第三方库,所以只能从微信小程序的模块化入手。</p>    <p>文档中提到,模块化的关键是:</p>    <pre>  <code class="language-javascript">module.exports = function(){}</code></pre>    <p>同时,如果我们去观察小程序开发环境的 network 面板,点击任何一个js,我们可以发现:</p>    <ol>     <li> <p>项目目录中的 所有js文件都会自动被加载,无论我们是否在代码中 require</p> </li>     <li> <p>所以的模块都会被套上下面的代码:</p> </li>    </ol>    <pre>  <code class="language-javascript">define("reducers/visibilityFilter.js", function(require, module){var window={Math:Math}/*兼容babel*/,location,document,navigator,self,localStorage,history,Caches;    /********************/  /******你写的代码******/                                                                   /********************/    })</code></pre>    <p>这实际上是类似 <a href="/misc/goto?guid=4958870939393898887" rel="nofollow,noindex">AMD</a> 的加载方式,但是跟标准的AMD又有些不同,缺少了依赖部分的声明。</p>    <p>function(require, module){} : 这个函数包裹的是模块的实现,也就是我们自己写的代码,小程序给我们暴露了两个参数 require 和 module ,require用来在模块中加载其他模块,module用来将模块中的方法暴露出去:</p>    <pre>  <code class="language-javascript">module.exports = function(){}</code></pre>    <p>所以只要需要让第三方库的代码使用这种形式的export就可以了。</p>    <h3><strong>构建Redux的微信小程序包</strong></h3>    <p>这里主要目标是打一个Redux包,让它可以兼容微信小城的加载方式</p>    <ol>     <li> <p>下载Redux的代码到本地</p> <pre>  <code class="language-javascript">git clone https://github.com/reactjs/redux.git</code></pre> </li>    </ol>    <ol>     <li> <p>安装依赖</p> <pre>  <code class="language-javascript">npm install</code></pre> </li>     <li> <p>打包</p> <pre>  <code class="language-javascript">npm run build:umd && npm run build:umd</code></pre> </li>    </ol>    <p>这些命令的详细内容可以到redux项目的package.json中查看。</p>    <p>这些命令是是使用webpack构建UMD模式的包。也就是说所有的代码,包括依赖的库都会被打包到一个文件中,并且自带一段模块加载代码,文件可以在 dist 目录下找到。</p>    <p>带min.js后缀的是minify过的。</p>    <ol>     <li> <p>微调加载方式</p> </li>    </ol>    <p>用编辑器打开dist目录下的redux.js文件</p>    <pre>  <code class="language-javascript">(function webpackUniversalModuleDefinition(root, factory) {      if(typeof exports === 'object' && typeof module === 'object')          module.exports = factory();      else if(typeof define === 'function' && define.amd)          define([], factory);      else if(typeof exports === 'object')          exports["Redux"] = factory();      else          root["Redux"] = factory();  })(this, function() {  ...    })</code></pre>    <p>这段代码是用来加载模块的,里面的factory函数的返回的内容是用webpack提供的loader组织起来的redux的代码和第三方依赖。</p>    <p>如果我们把这个文件拷贝到小程序中,只需要让程序能正常进入第三行代码,就能把Redux加载进来。</p>    <p>将第二行代码:</p>    <pre>  <code class="language-javascript">if(typeof exports === 'object' && typeof module === 'object')</code></pre>    <p>修改成:</p>    <pre>  <code class="language-javascript">if(typeof module === 'object')</code></pre>    <p>这样修改的原因是,在微信小程序的环境中是没有 exports 变量的,所以就没办法正确进入这个分支,删除之后就可以正确进入了</p>    <ol>     <li> <p>拷贝进工程目录</p> </li>    </ol>    <p>例如,我们拷贝到 libs 目录下,那么我们在程序中使用时,只要当做是一个本地模块去require就可以了:</p>    <pre>  <code class="language-javascript">var redux = require('./libs/redux.js')</code></pre>    <p>通过这里的示例,其实我们发现,我们可以通过类似的方法,使用Webpack打包第三方库,就可以集成任何库了。</p>    <h2><strong>使用Redux</strong></h2>    <p>我们可以使用Redux的微信小程序绑定库来简化一些代码: <a href="/misc/goto?guid=4959719922654926781" rel="nofollow,noindex">wechat-weapp-redux</a> ,</p>    <p>详细的安装和使用说明可以参照 <a href="/misc/goto?guid=4959719922654926781" rel="nofollow,noindex">wechat-weapp-redux</a> 的README</p>    <h2><strong>集成Redux-</strong>devtools</h2>    <p>如果没有redux-devtools那么使用redux的效果可能是要减半的。</p>    <p>因为微信小程序的开发环境是定制的,暂时没有发现办法直接安装redux-devtool的插件。</p>    <p>这里使用 <a href="/misc/goto?guid=4959719922756686734" rel="nofollow,noindex">remote-redux-devtools</a> , <a href="/misc/goto?guid=4959719922835101699" rel="nofollow,noindex">remotedev-server</a></p>    <ol>     <li> <p>安装remote-redux-devtools</p> </li>    </ol>    <p>原版的remote-redux-devtools使用的一个websocket的依赖会使用原生的WebSocket,小程序是不支持的,所以需要改成小程序的websocket实现。</p>    <p>修改好的包在这里: <a href="/misc/goto?guid=4959719922925480833" rel="nofollow,noindex">remote-redux-devtools</a></p>    <p>把代码下载到工程目录里面就可以用了。</p>    <ol>     <li> <p>安装和启动remotedev-server</p> <pre>  <code class="language-javascript">npm install -g remotedev-server  remotedev --hostname=localhost --port=5678</code></pre> </li>    </ol>    <p>因为没办法用npm安装到本地(开头提到的,微信小程序会尝试去加载项目目录中的所有js),所以这里使用全局安装,第二条命令是启动remotedev-server,hostname和port分别指定为localhost和5678。</p>    <ol>     <li> <p>集成devtool</p> <pre>  <code class="language-javascript">const {createStore, compose} = require('./libs/redux.js');  const devTools = require('./libs/remote-redux-devtools.js').default;  const reducer = require('./reducers/index.js')    function configureStore() {    return createStore(reducer, compose(devTools({      hostname: 'localhost',      port: 5678,      secure: false    })));  }    module.exports = configureStore;</code></pre> </li>    </ol>    <p>把devtool使用redux的compose加到store中去。</p>    <p>hostname和port是指定为之前启动remotedev-server启动时候指定的参数。</p>    <p>保存之后重启一下小程序,如果没有报错的话就OK了</p>    <ol>     <li> <p>打开监视器</p> </li>    </ol>    <p>可以在浏览器中访问 <strong>localhost:5678</strong> ,这是remotedev-server自带的监视器,正常打开的话是这样的:</p>    <pre>  <code class="language-javascript">![redux-devtools-monitor][2]</code></pre>    <p>左边有一个 @@INIT 说明小程序的redux连接成功了。</p>    <p>但是这里这个自带的监视器可能打不开,因为它的一些js包是存在国外的cdn上的,偶尔访问不到。</p>    <p>这个时候可以使用 <a href="/misc/goto?guid=4959719923008558941" rel="nofollow,noindex">http://remotedev.io/local/</a> ,点击下面的 setting ,设置使用本地的server。保存之后刷新页面,应该跟上面显示的结果一样。</p>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000007107646</p>    <p> </p>