My Little World

构建

UI库

ant design 适合企业级应用,复杂交付,密集数据展示
material UI:时尚,花哨,具有的美观性,更适合开发面向消费者的应用(google版原始react实现)
sematic UI:把UI当做一种language来描述(jquery版原始react实现)

选择UI库的考虑因素

  1. 组件库是否齐全(齐全的话可以减少很多工作量,不用自己实现)
  2. 样式风格是否符合业务需求(企业级应用一般要求简洁明了,对于密集性数据展示比较合理;对于移动端面向消费者一般要求好看,button,字体比较大)
  3. API 设计是否便捷和灵活(使用起来是否方便,从而会影响开发效率)
  4. 技术支持是否完善(技术文档是否齐全;github上提issue时,能不能得到快速解答)
  5. 开发是否活跃(是否有稳定团队在进行快速迭代和维护,在遇到BUG或者需要新功能时可以得到满足)

使用next.js 构建react 同构应用

同构应用:浏览器第一次向服务器请求页面时,服务器返回解析好的页面,不需要浏览器执行js来进行渲染(这样可以加快页面首次打开的速度),之后页面的操作/切换,像单页面一样,不需要浏览器刷新,均由前端完成,包括UI渲染,页面路由切换等,不需要再向服务端请求页面

next.js的几个规则
1.页面就是pages目录下的一个组件
所有页面放在pages文件夹下,一个页面即一个组件,文件名和文件路径对应路由路径
2.static目录映射静态文件(图片)
3.page具有特殊静态方法 getInitialProps
next.js提供给react组件初始化props的方法

命令行装包:

1
npm install --save react react-dom next

在页面中使用其它 react 组件
1.页面也是标准的node模块,可使用其它 react组件
2.页面会针对性打包,仅包含其引入的组件
,不会加载其他额外的资源

所有组件放在components文件夹下,在pages文件夹下的页面js中使用时,直接用路径import进去

使用Link实现同构路由

1.使用 next/link 定义链接

1
2
3
4
5
import Link from 'next/link'
export default ()=>
<div>
<Link href='/about'><a>here</a></Link>
</div>

2.点击链接时页面不会刷新
如果使用a标签会产生刷新

3.使用 prefatch预加载目标资源
如果不添加该属性,则链接对应的组件,在切换的时候再加载相应页面打包的内容,有该属性,则next.js 打包时就会获取所有链接对应的组件,会预加载所有的js内容,从而提高页面切换速度,但是并不会预加载需要从服务器端API请求的数据

4.使用 replace 属性替换 url
替换当前页在路由中的history,无法后退回当前页

动态加载页面

1
2
3
4
5
6
import dynamic from 'next/dynamic'
const DynamicComponet=dynamic(import('../components/hello'))
export default ()=>
<div>
<DynamicComponet/>
</div>

页面在加载时,除了加载整个页面的main.js,还会加载动态加载的组件的js包,当这个动态组件被render的时候才会被加载

测试

react 让前端单元测试变得容易
1.react 应用很少需要访问浏览器 API
2.虚拟 Dom 可以在 NodeJs 环境运行和测试 (不需要浏览器环境,在内存中render虚拟DOM即可完成测试)
3.Redux隔离了状态管理,纯数据层单元测试

单元测试涉及的工具
1.Jest: Facebook 开源的 JS 单元测试框架 (零配置,可以直接开始测试)
2.JS dom浏览器环境的 NodeJS 模拟 (一个在nodejs中可以模拟浏览器的library)
3.Enzyme:React组件渲染和测试 (在nodejs中渲染虚拟DOM进行测试,通过进行不同程度的render(shallow Rendering,Full Rendering,Static Rendering,进行不同程度的测试,比如利用shallow Rendering浅渲染测试渲染结果是否符合预期的DOM结构)
4.Nock: 模拟 HTTP请求 (模拟得到请求返回数据)
5.Sinon: 函数模拟和调用跟踪 (例如测试组件UI时,跟踪响应函数有没有被调用,调用几次,而不是去测试响应函数是否符合预期,测试响应函数是否符合预期属于响应函数测试范畴。集成在JEST中)
6.istanbul:单元测试覆盖率(通过对已有代码的修改和埋点去判断相关代码有没有被执行到)

开发调试工具

eslint
1.使用 .eslintrc 进行规则的配置
2.使用 airbnb 的 JavaScript 代码风格

检查语法风格,拼写错误,会报错,保证代码的一致性

Prettier
vscode 的一款插件,根据一定规则做代码格式化 .eslintrc
1.代码格式化的神器
2.保证更容易写出风格一致的代码
不会报错,会直接根据规则将代码格式化

React DevTool chrome插件
定位组件,可以以组件树的形式查看DOM结构,
勾选highlight updates可看到需要更新的组件

Redux DevTool chrome插件
可查看action和action引起的变化
time machine 功能,可以回溯action,方便观察loading过程,进而对loading进行优化
可自动生成测试代码

理想架构

易于开发(但可能会不容易扩展和维护)
1.开发工具是否完善 (采用的技术栈是否有相应的开发工具来支持)
2.生态圈是否繁荣 (是否有类似项目遇到过相同问题可以借鉴)
3.社区是否活跃(提问有人回答)

易于扩展
1.增加新功能是否容易
2.新功能是否会显著增加系统复杂度(系统放大之后会难以扩展和维护,考虑引进新功能时,如何架构能保证减少系统复杂度的提高)

易于维护
1.代码是否容易理解 (基于一定的最佳实践规范去编写,保证多人开发有一定的规则)
2.文档是否健全(通过注释,架构图,具体文档描述项目中的一些关键点,方便后续工作人员查看,也方便日后回头开发能快速理解关键点,来维护已有项目)

易于测试
1.功能的分层是否清晰 (UI,数据层之间依赖少)
2.副作用少 (模块高内聚,对外部依赖少)
3.尽量使用纯函数(输入决定输出,确定)

易于构建
1.使用通用技术和架构 (保证现有项目不需要定制化,就可以打包部署)
2.构建工具的选择(webpack ,roolup,使用常用技术栈,减少额外配置)

大型前端应用需要拆分复杂度原因
当项目增加更多功能的时候,项目复杂度并不会指数级的上升,始终保持在一个可控的范围之内

拆分复杂度技术架构

从功能上进行区分,将业务逻辑拆成高内聚松耦合的模块,每个模块负责一个功能,拥有自己的componet,action和reducer,这样即使当一个功能需要删除时,只要删除相应的模块即可,也保证其他模块不受影响;路由不再由一个文件统一定义,每个feature自己定义一个路由,然后由route的loader把每个模块的路由文件加载进根结点的routing文件

技术上的component,路由,reducer是按照功能的方式组织在模块上

如何组织 component,action 和reducer
文件夹结构
• 按 feature 组织源文件
• 组件和样式文件同一级
• React 单独文件夹
• 单元测试保持同样目录结构放在 tests 文件夹

组件和样式组织
一个功能的组件js和样式文件放在一个模块中,再由一个index.js引入各个模块的组件js文件,一个style文件引入各个模块的样式文件,进行统一管理输出,打包时就只是打包index.js和style文件
注意:
如果组件中引入样式文件,那么当这个组件被重复使用时,样式文件会被多次引入,打包时就会多次进行打包,造成不必要的代码冗余
使用上述加载方式,样式文件独立加载,js文件只需要加载它所需要的资源,就不会发生多次加载

action 和 reducer组织
一个模块的,action 和 reducer 一一对应放在同一文件,再由一个actions.js引入所有action,一个reducers.js引入所有reducer,这两个文件只是充当loader的角色
好处:action 和 reducer 非常小,不会被无限的去扩展,更容易理解

CONSTANTS.js中命名的常量一功能名开头,避免与其他模块常量命名冲突

再由rootreducer加载所有模块下的reducer,进行combineReducers挂载,实现全局使用

优点:一个模块内部是高内聚的,各个模块之间是松耦合的

主要思想:使用 root loader 加载 feature的各个资源

路由配置
每个模块(页面级)路由通过export JSON格式数据 ,自己配,再loader到根路由,由根路由统一处理解析json格式为react Router的声明式形式

每个模块都有都有自己的专属路由配置
顶层路由使用JSON配置更易维护和理解