react开发文档(react怎样实现页面代码分割和按需加载)

本文目录
- react怎样实现页面代码分割和按需加载
- React:项目下的reportWebVitals.js文件
- 如何在React中调用微信的jsSDK
- react-router、react-redux、antd(Layout)
react怎样实现页面代码分割和按需加载
这次给大家带来react怎样实现页面代码分割和按需加载,react实现页面代码分割和按需加载的注意事项有哪些,下面就是实战案例,一起来看一下。
虽然一直有做 react 相关的优化,按需加载、dll 分离、服务端渲染,但是从来没有从路由代码分割这一块入手过,昨天在本地开发时没有测试成功,今天又搞了下,已经部署到线上环境了,今天就这个记录一下。
修改配置
开发环境:webpack@v3 、react-router@v4
安装依赖:
$ yarn add babel-plugin-syntax-dynamic-import -dev修改 .babelrc 文件:在 plugins 中添加 "syntax-dynamic-import"
改造项目代码
安装依赖:
$ yarn add react-loadable根据 react-loadable 文档提示,我们需要提供一个载入新页面时的 Loading 组件,同时对加载和超时状态进行区别提示:
import React from ’react’;
import { Icon } from ’antd’;
const Loading = ({ pastDelay, timedOut, error }) =》 {
if (pastDelay) {
return 《p》《Icon type="loading" /》《/p》;
} else if (timedOut) {
return 《p》Taking a long time...《/p》;
} else if (error) {
return 《p》Error!《/p》;
}
return null;
};更改页面组件导入方法:
import React from ’react’;
import Loadable from ’react-loadable’;
import { Route, Switch } from ’react-router-dom’;
const Home = Loadable({
loader: () =》 import(’../Home’),
loading: Loading,
timeout: 10000
});
const EditArticle = Loadable({
loader: () =》 import(’../EditArticle’),
loading: Loading,
timeout: 10000
});
...
《Switch》
《Route exact path="/home" component={Home} /》
《Route path="/editarticle" component={EditArticle} /》
《/Switch》然后打包结果就会分离出各页面代码:
在页面中我们只需要载入入口文件 app.js ,其他脚本在访问到对应页面时都会经由这个文件载入。
验证结果
在将静态资源上传到 cdn 之后,在页面中加载 app.css 和 app.js ,运行之后访问各个页面就会依次加载对应脚本,结果如图:
可以看到,在访问第一个页面时加载的页面脚本经 gzip 压缩后仅有 21.8KB !!!当然这与页面复杂度也有关,但是相较于加载全部脚本,已经是大幅减少了,这种优化对访问目标性很强的用户感受起来尤为明显。
这么做的另一个好处就是当我们只更改项目中某些页面的业务代码时,其他页面的代码依然是不变的,所以这个时候其他页面用的是客户端缓存,从另一个层面又做了一次优化。
Tips
相信看了本文案例你已经掌握了方法,更多精彩请关注Gxl网其它相关文章!
推荐阅读:
react实现手机号的数据同步
本地开发怎么使用node服务器跨域
React:项目下的reportWebVitals.js文件
最近在用react搭建项目,发现react的脚手架升级了,在项目根目录下发现了一个新的文件 – reportWebVitals.js。很好奇这是个啥。
reportWebVitals.js内容如下:
里面有些比较熟悉的字母CLS、FID、FCP、LCP、TTFB这些跟性能指标有些关系的。
然后第三行有引入一个web-vitals的库。在npm上搜到了 web-vitals
create-react-app 官网中也有一篇文档 Measuring Performance 来描述在react项目中使用web-vitals。
运行项目:
控制台采集到的数据
如何在React中调用微信的jsSDK
1. 微信JSSDK使用步骤简介
我们既然是在做基于微信的开发,当然就离不开微信的开发文档了。开始之前希望大家能先去看下《微信JS-SDK说明文档》。那么我们怎么样才能用上微信的JSSDK呢?以下基本步骤就是基于该文档的。
需要注意的是,如果本人下面的描述你看的有点云里雾里的话,我建议你:
回头看下本系列《小白学react》的历史基础文章,特别是《小白学react之altjs的Action和Store》以及《小白学react之打通React Component任督二脉》,或/和:
直接跳过我的描述,在文章后面下载最新的源码,先阅读源码,碰到问题再反过来看文章的描述。
- 《% for (var chunk in htmlWebpackPlugin.files.chunks) { %》 《script src="《%= htmlWebpackPlugin.files.chunks.entry %》"》《/script》
- 《script src="jweixin-1.0.0.js"》《/script》
- 《% } %》
- wx.config({
- debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
- appId: ’’, // 必填,公众号的唯一标识
- timestamp: , // 必填,生成签名的时间戳
- nonceStr: ’’, // 必填,生成签名的随机串
- signature: ’’,// 必填,签名,见附录1
- jsApiList: // 必填,需要使用的JS接口列表,所有JS接口列表见附录2});
- window.wx.config({
- ...
- });
- wx.ready(function(){ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。});
- wx.error(function(res){ // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。});
- wx.config({
- debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
- appId: ’’, // 必填,公众号的唯一标识
- timestamp: , // 必填,生成签名的时间戳
- nonceStr: ’’, // 必填,生成签名的随机串
- signature: ’’,// 必填,签名,见附录1
- jsApiList: // 必填,需要使用的JS接口列表
noncestr:一个随机字符串,我们随便填写
jsapi_ticket:jsapi_ticket是公众号用于调用微信JS接口的临时票据
timestamp: 签名时间戳。注意这个时间戳需要和上面传入wx.config的时间戳一致
url: 调用JS接口页面的完整URL。我们可以从react客户端通过location.href获得,并传给服务器端
url: react客户端传进来的需要注入jsapi的页面url
callback: 一个回调函数,接受一个json格式的参数。主要是用来将生成的签名信息等回传给上层调用函数。
- const config = { grant_type: ’client_credential’, appid: ’xxxx’, secret: "xxxxx", noncestr:’Wm3WZYTPz0wzccnW’, accessTokenUrlin.qq.com/cgi-bin/token’, ticketUrl:’com/cgi-bin/ticket/getticket’,
- }
- exports.sign = function (url,callback) { var noncestr = config.noncestr,
- timestamp = Math.floor(Date.now()/1000), //精确到秒
- ...
- request(config.accessTokenUrl + ’?grant_type=’ + config.grant_type + ’&appid=’ + config.appid + ’&secret=’ + config.secret ,function(error, response, body){ if (!error && response.statusCode == 200) { var tokenMap = JSON.parse(body);
- request(config.ticketUrl + ’?access_token=’ + tokenMap.access_token + ’&type=jsapi’, function(error, resp, json){ if (!error && response.statusCode == 200) { var ticketMap = JSON.parse(json);
- cache.put(’ticket’,ticketMap.ticket,config.cache_duration); //加入缓存
- callback({ noncestr:noncestr, timestamp:timestamp, url:url, jsapi_ticket:ticketMap.ticket, signature:sha1(’jsapi_ticket=’ + ticketMap.ticket + ’&noncestr=’ + noncestr + ’×tamp=’ + timestamp + ’&url=’ + url)
- });
- }
- })
- }
- })
- }
- }
- app.get("/api/signature", function(req,res) { const url = req.query.url.split(’#’);
- signature.sign(url,function(signatureMap){
- signatureMap.appId = wechat_cfg.appid;
- res.send(signatureMap);
- });
- })
- {
- noncestr: ’Wm3WZYTPz0wzccnW’,
- timestamp: 1476873698,
- url: ’com/?code=001kGsd30xcm7F1PAFf305Uud30kGsdr&state=’,
- jsapi_ticket: ’sM4AOVdWfPE4DxkXGEs8VBqyVbs-TKGYp4d_ZSQa0Q5WvvMUPNQ6XGpyEcgKOD_xID_GrMCaalSmIF9JbrGaOg’,
- signature: ’9268ffaf4b9eb0d296fcfefe3d2724118aa05e3c’
- }
- var WechatSdkSource = {
- fetchSignatureMap() { return {
- remote(state,url) { return co(function *() { let signatureMap = null; const getSignatureMapUrl = `/api/signature`; try { let result = yield request.get(getSignatureMapUrl).query({url:url});
- signatureMap = result.body;
- } catch (e) {
- signatureMap = null;
- } //console.log("userInfo:", userInfo);
- return signatureMap;
- });
- },
- local() { // Never check locally, always fetch remotely.
- return null;
- }, success: WechatSdkActions.updateSignatureMap, error: WechatSdkActions.getSignatureMapFailed, loading: WechatSdkActions.getSignatureMap,
- }
- }
- };
- var alt = require(’../alt’);module.exports = alt.generateActions( ’updateSignatureMap’, ’getSignatureMap’, ’getSignatureMapFailed’,
- );
- class WechatSdkStore { constructor() { this.signatureMap = ; this.errorMessage = null; this.ready = false; this.bindActions(WechatSdkActions); this.exportAsync(WechatSdkSource);
步骤一:绑定域名
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
备注:登录后可在“开发者中心”查看对应的接口权限。
***隐藏网址***
步骤二:引入JS文件
***隐藏网址***
***隐藏网址***
,否则将无法在iOS9.0以上系统中成功使用JSSDK
因为我们的index.html是通过ejs模版生成的,所以我们只需要在我们的index.ejs中的body部分末尾加入相应的微信jssdk库的引用就好了。
步骤三:通过config接口注入权限验证配置
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。
这一步的关键是如何生成正确的签名。这里微信jssdk文档中有给出不同语言版本的签名算法示例大家可以参考。往下我们也会就github上的一个签名算法的封装进行学习。
在我们的实战过程中,签名会在服务器端发生。
react客户端会像之前的获取微信用户信息一样,通过一个restfulApi调用服务器端的api,然后由服务器来生成对应的签名,然后将签名信息返回给客户端。
客户端获取到上面wx.config示例代码中的签名相关信息后,就会调用一个Alt的Action,来触发将获取回来的信息保存到一个跟该Action绑定的jssdk状态管理的Store里面。然后就可以调用wx.config来配置我们需要用到的JS接口列表了。
注意这里的wx这个对象是通过上一步的JS文件引入进来的。我们在react的客户端代码中可以直接通过window.wx对其进行引用:
步骤四:通过ready接口处理成功验证
随后,react客户端负责jssdk状态管理的store会调用wx.ready来监听config配置是否成功,如果成功的话,就会将该store的一个ready状态设置成true。
这样的话,通过AltContainer绑定了该store的相应的Component组件就能知道响应的jssdk的api是否已经准备就绪,可以进行调用了。
步骤五:通过error接口处理失败验证
同理,如果如果配置失败的话,那么就在wx.error这个监听接口中将ready状态设置成false。
2. 生成签名
如前面所述,我们需要用到jssdk的页面必须要要注入调用到的api的配置信息。
而注入JS接口到页面时,我们可以看到,还需要使用到其他一些信息。其中appId我们可以从公众号管理后台获得。signature是跟所访问页面的url关联的一个签名,它有专门的一套算法来生成。另外两个参数nonceStr和signature都是在签名的过程中生成的。
这里通过wx.config传进去这些参数,主要是为了让微信去判断我们生成的签名和微信通过这些信息生成的签名是否一致,如果不一致的话,那么注入到该页面的jsApiListj就失败。
那么我们在服务器这边的签名算法是如何的呢?根据微信开发文档我们需要提供以下4个参数,然后通过sha1算发来生成对应的签名:
那么这里主要需要解决的就是如何获得jsapi_ticket这个临时票据了。
根据文档的描述,我们可以通过以下这个接口获得:
cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
从中可以看到,我们调用这个接口首先要获得一个access_token。这里微信也有相应的api来处理。
cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
这里需要用到我们的微信公众号的appId和secret,这些我们都是已知的,所以好办。
那么,也就是说,我们其实只需要提供我们的微信公众号的appId和secret,就能获取到access_token,从而就会获得我们需要的jsapi_ticket。
这里我们参考下github上一个示例(wechat-sdk-demo )的签名的实现。其传入的参数有两个,其中:
这里的流程和我们刚才描述的并无二致。首先是通过appId和secret获得调用获取jsapi_ticket的access_token,然后通过该access_token获得我们签名需要用到的jsapi_ticket。noncestr我们是提前随便填写好的。timestamp的算法也比较简单。
最后就是通过sha1这个库提供的方法,将jsapi_ticket,noncestr,timestamp和页面url进行sha1签名,然后将以上这些信息通过callback返回给上层调用函数。
那么我们往下看下我们的上层调用函数。其实就是我们的express路由:
根据微信开发文档需求,我们首先需要将传进来的url的锚点后面的数据给去掉,保留前面的有效部分。
然后就是调用上面的sign方法来生成签名。上面的签名方法最后传进来的json数据就是这里的signatureMap。我们最终会将这些数据发送回react客户端。
同时,通过上面的wx.config的示例,我们知道还需要用到微信公众号的appId。所以这里一并将其放到signatureMap中进行返回。
那么到此为止,react客户端调用服务端的"/api/signature"返回的数据示例如下:
3. 客户端获取签名信息
3.1 获取签名信息并注入jssdk
和之前的获取微信用户信息一样,我们这里会建立一个新的Source文件WechatSdkSource.js来调用远程服务器的"/api/signature"接口:
这里传进来的url由下面将要谈及的上层函数所生成。整个流程就没有什么好说的了,说白了就是通过相应的库发送一个带有url的query参数的请求到服务器端来请求签名信息,相信有跟着这个系列文章的朋友都是很清楚的了。
最终请求成功返回的时候就会调用WechatSdkActions的updateSignatureMap这个Action。
而这个action就会触发所监听的WechatSdkStore的onUpdateSignatureMap这个回调。
react-router、react-redux、antd(Layout)
文档中的简介:React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。
在我看来(我是做iOS开发的),这就像是 iOS 里面呢的 UITabbarController 和 UINavigattionController 的结合一样,控制着各个 ViewController 的跳转;不同的是react-router可以控制Route所在的位置,而iOS已经固定状态栏、导航栏、tabbar位置、高度,只能控制其隐藏和显示。
文档中介绍:Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
我的理解是:此组件是对 model 或 viewModel 进行管理,解放我们对 setState 的操作;同时实在管理的时候可以进行一些中间件(applyMiddleware)操作,如:loggerMiddleware 等。
一个很丰富的UI组件库。题目中提到的 Layout 是我在开发过程中用到的布局样式。
如果单独只用这些组件中的某一个,根据文档都可以做得很好。但是三者一结合使用,就有一些问题了。
我的做法是将 Route 放到 Content 里面,共用 header ,类似于 iOS 里面的 tabbar 一样。在 header 里面添加 Link 标签,控制其切换、跳转。
此时会有一个问题,登录界面,并不要 header 的显示。于似乎,在经过多次尝试(可能并不是最优的),我在 index.js 的外层加了一个 Switch,将 index 放到 Route 里面。此处用 Window 命名是根据 iOS 开发里面的层级命名的,并不是js里面的window。
在需要跳转登录界面的时候,this.props.history.replace("login")
跳转下级路由的时候,this.props.history.push("detial")
这就导致 react-router 的跳转出现了一些问题。this.props.history 为 undefine 。这样的话,就不能跳转了啊。
尝试零:是不是在mapStateToProps方法里面把 history 给传丢了?补充一下,结果并不能解决。
尝试一:在跳转的时候,window.location.href("llogin"),这样是可以实现的,但是每次页面都会刷新,react-router的意义何在?
最终,在 react-router-dom 里面提供了 withRouter,将 withRouter 放到 connect 外面就好了。
另外每个页面可能都需要一个 Provider,但是整个项目只能有一个 Router,所以并不能像 redux 文档 里面那样些写。而应该将 Router 放到 Provider外面(我是这么写的,而且可以用没警报。但不确定是百分之百有道理的)。

更多文章:
he agreed to help(用need to do sth.和agree to do sth. 造句)
2026年8月31日 01:00
instr函数的返回值(关于vb中InStr函数的一个小问题)
2026年1月26日 22:30
slcp是什么意思(matlab.*和matlab. s有什么区别)
2026年1月3日 12:00
db2数据库update后想恢复(你好,SQL修改错了,修改前没有备份,请问怎么还原到修改前的数据,你知道吗可以给联系方式我请教一下)
2026年9月17日 12:00
assert python用法(python:assert_raises() 怎么用啊,有哪些参数 请说得详细些,先谢谢了!)
2026年7月11日 08:30
this is it歌词好诡异(Turn The Lights On的歌词翻译)
2025年7月26日 02:30
tabletennis安卓游戏(table tennis touch多人游戏时提示game center断开链接怎么解决)
2025年8月8日 17:15
迷你qq头像(2021头像可爱呆萌男生,寻找一些头像小男孩的那种)
2026年2月14日 13:00















