写在前面
项目来自于今年中国软件杯赛题:基于WIFI探针的商业大数据分析技术
赛题包括探针程序,数据分析程序,展示界面等,我做的是可视化展示部分和后台管理页面
这个仓库是数据可视化程序,将分析好的数据可视化的展示出来
因为后台是java写的,为了简单的产生数据,我用node写了个小后台,提供数据
可直接到我的服务器看:47.93.254.91:3000
源码地址:https://github.com/ooooevan/react-redux-echarts
功能结构
调试运行
|
|
打开数据后台
|
|
我已经把打包好的dist文件拷贝到server的静态目录下,所以打开数据后台可以直接访问localhost:3000看到页面
修改后打包
|
|
生成的文件在dist
目录中。
因为是windows下,需要手动复制静态文件:
将lib
目录复制到dist
目录下,将favicon.ico
复制到dist
目录下。
页面截图
使用的相关技术
- 使用es6写法,安装一堆babel插件(现在有babel-preset-env可以少很多了)
- react、react-redux、react-router,页面结构较多,这样用是比较合适的。当然也可以用mobx
- 使用了不可变数据,因为要渲染的数据层级深,用immutable很有必要
- 使用webpack2做模块化,打包,做了代码分割加快首屏渲染
- 使用百度的echarts做可视化
总体分析
目录结构
|
|
再看src
目录下的结构:
数据流向
总体流向
使用的是redux,当然是 components->actions->reducers->components
举个具体的例子
打开一个组件
要经过的地方:
所有的数据流向都是这样,很清晰
项目遇到的问题
1. echarts实例对象放哪里
因为ehcarts要先初始化才能显示一个loading的图像,等数据返回才能渲染数据,但是这个实例化的对象放哪里呢?
一开始我把这个对象跟数据的流向一起,把对象当做参数,带到action再到reducer。
虽然这样也成功了,但是我发现,reducer是纯函数啊,怎么可以做这么不纯洁的操作呢,然后才想到,应该存在组件的state中。。
因为这个对象本身不是用来显示数据的,所以不用this.setState()而是直接赋值
这应该是个很弱智的问题,但是当时就是困扰了我。。
2. 数据层级深导致数据出问题
echarts要求的数据格式层级很深,随便就3,4层嵌套(应该所有的可视化数据都是这么深)
在没有引入immutable时,我想让数据尽量快点渲染,在componentWillReceiveProps里执行渲染操作,却犯了个错误
当我发现这个错误时,却发现这么大错误没有导致页面任何异常。。
通过debugger才知道,原来我执行reducer时更改了原state,所以到这里时,this.props就等于nextProps
而更改了原state,肯定就是因为数据层级嵌套太深导致的。所以才引入的immutable,不改变原数据,返回新数据
immutable和原生js对象不一样,不能互相使用方法的方法,所以引入immutable要多记几个api
两种对象互转比较消耗性能,能不转就不转,而且如果要在shouldComponentUpdate手动判断更新的话,用immutable很容易。
我这里的转化:reducer拿到服务器数据即转为immutable->更新state->组件使用->echarts渲染函数接收的参数要原始对象,所以在这里转为原始对象
immutable对象也有像原始对象那样一系列函数如map、forEach等,基本满足数据渲染要求,所以如果项目中没有echarts这样必须使用原始对象的,可以一直用immutable对象
还有就是combinereducer不支持immutable,需要用redux-immutable
库重写了的combinereducer
3. 打包文件过大
打包生成最终文件,好几兆,太大,于是寻找减少大小的方法
webpack配置压缩文件
12345678new webpack.optimize.UglifyJsPlugin({output:{comments:false, //去掉所以注释},compress:{warnings:false}}),代码切割,根据路由分成多个小文件,按需加载
有两个地方需要改:
1、路由123456789//原来import Statistics from './statistics/statistics';<Route path="statistics" component={Statistics} />//现在const Statistics = (location, callback) => {require.ensure([], (require) => {callback(null, require('./statistics/statistics').default);}, 'statistics');};
2.webpack配置
这样能分隔出多个文件,加载时只需加载公共的vendors和此路由需要的js文件,大大加快了首屏渲染
并且,用chunkhash能做版本控制,在修改代码后,只会使修改的部分文件的哈希改变,其他文件都没有变,这样,只需要看名字有没有变就可以知道哪些文件更新了,对部署很有帮助,请看:大公司里怎样开发和部署前端代码?
其他
函数去抖
因为echarts图像是canvas绘制的,当改变浏览器窗口大小时发现canvas不会变,此时要重新绘制图像。调用echarts提供的方法。并且是在window.resize触发时执行
仅仅这样会发现,改变窗口大小时,会一直触发这个函数,就行onmousemove那样一直触发,这样就很浪费性能,严重会引起假死状态,所以要用函数去抖(类似还有函数节流)
代码很简单,监听resize事件,然后设置定时器,只要一定时间范围内又触发,则重新计时,知道最后不触发了再执行
缺点
由于是已经结束的项目,就想不再修改了,但是缺点还是在的
- 最大的缺点就是组件重用,大部分图形组件都是一样的,是可以共用一个组件,将数据传入进去的,我却一个图形一个组件,所以项目的这么多图像组件基本都是一样的
- scss没有模块化,开始想共用一些代码就没有分离,然后变成了全部样式全挤在一个文件里。。
- propTypes没写好,没有用typescript,类型检查是很有必要的,但是我偷懒很多都没写
- 代码比较乱,很多代码和注释没有去掉
这个部分是比较简单的,业务很简单(其实还有个管理后台,因为没有写后台提供数据就不放出来了)。但对react的理解还是挺有帮助的,写代码时另一大问题就是react生命周期、路由等问题,写着写着就懂一点了。
这是过了挺久才做的总结,所以有些都忘记了,只能写这么多,如果有错,望指正