皇上,还记得我吗?我就是1999年那个Linux伊甸园啊-----24小时滚动更新开源资讯,全年无休!

记一次 fis3+react 开发经历

前言:

虽然说是记录 fis3+react 的一次开发经历。但是在项目的上线前几天收到公司 TC 委员会的邮件,因为 react 的开源协议让找到 react 的替代方案,并且逐步下线线上的 react 项目。真的是可以用“出师未捷身先死”来形容这次开发了。

不过经过调研以后发现在业界已经有了一些开源方案来替代 react 。最有名的就是 preact 的了吧。而且按照官网的方案来做迁移的话,迁移的成本也挺小的。后续会介绍下迁移的情况。本文也是主要介绍下,使用 react+fis3 开发的一些经验和其中遇到的问题的解决方案。

下面的文章也统一用 react 这个名词。

1. 为什么要使用 react+fis3

目前在选择使用 Vue 或者是 React 的时候,总要说些为什么要用。其实我的想法很简单。因为我们的产品是偏向业务型的,复杂的数据交互不多,但是流程多,而且很多业务要复用一些页面流程。按照我们旧的开发模式来说,我们的模板文件存在着很多的 if...else 来做流程判断。这样对于我们维护项目来说是非常的不方便的。我们希望引入一项技术来解决不同流程公用一些页面的问题,而且可以在不同的流程中自定义这个页面的表现的技术。

React 的组件思想是一种解决方案。页面的每一个元素都可以作为一个组件来抽象。扩大到一个页面也可以作为一个组件。所以这是我选择 React 来开发我的页面。

按照业内主流做法使用 react 搭配 webpack 是最主流的。但是在公司内主推 fis3 的情况下还是选择了 fis3。而且 fi3 的维护团队也产出过一篇引导文章和 demo 来介绍使用 fi3 开发 react 应用(参考文章见文章末尾)。

在项目开始前也在分析要不要引入 redux。我们的页面是偏向业务的,很多页面都是表单的提交和验证。并没有很多的状态需要维护,而且我们的数据源也很单一。不过在经过一个页面的开发后还是发现一些页面引入 redux 会对开发工作带来很大的便利。

2. 项目的目录结构和作用

react 的开发模式基本上都差不多。因为这次我并没有引入 redux。所以我的目录结构也相对简单一些。如下:

3. 拆分页面

使用 react 的第一项工作就是要拆分自己页面。把自己的页面拆分成“一块一块”
的组件。所以看下图我的页面结构。

k25ud

我是这样拆分我的页面的,红色的线就是我的拆分模式。

sw0ht

所以我的 components 目录下的文件是这样的,分别对应这我对页面拆分后的组件。

而我的 comtainers 目录就是对应着我的页面文件,其实就是一个个零散组件的容器。

还有最有一个值得介绍的就是 routes 目录,管理整个项目的路由。

因为使用的 preact-router 这里的写法和 react-router 的有一些不同。代码如下:

4. 写 react 肯定会面临的问题

写 react 时,我们在享受着 react 的 visual dom 的高性能和不依赖 dom 的编程的便利时,面对最大的问题就是对组件的 state 的管理吧。当然最好的解决方案肯定是引入 redux 做状态管理。但是当我们没有引入 redux 时怎么办呢?

我先来举个简单的例子。我们有以下一个对像来管理页面的显示状态:

当我们的一个 state 嵌套太深时,按照我们使用 js 的一般做法要更新 header 的值的做法如下:

有时候我们为了能够让代码更健壮可能会这么写:

会发现这样做真的繁琐。当然我在做的时候也面临着这样的问题。通过查询相关资料,最佳的解决方案当然还是引入 redux。那么次佳的解决方案呢。其实就是引入第三方库,最具代表性的就是 facebook 自己的 facebook/immutable-js。这个库能让我们方便、安全、高效的更新一个 层次 较深的 state。但是也有一个缺点就是文件体积较大。当然与之相对应的就是开源大神做了优化后的版本 immutability-helperimmutability-helper

这三个库中文分析介绍的文档挺多的可以自行搜索了解。当然最后我上面的都没有用。因为之前的我的项目中已经引入了 lodash 这个开源库。而它也提供了较安全的更新一个深层次 object 的方法

如果使用 lodash 更新上面 header 的值,写法如下:

还有一个值得注意的地方就是在我们更新 state 之前,都是“克隆”而且是“深克隆”一个 state 去更新。“深克隆”肯定是会影响程序性能的,所以 facebook 的 facebook/immutable-js 提供了高效的方法去“深克隆”一个对象。

当然使用 lodash 也会更方便一些。但是这样的操作不应该经常的发生。

第三个,出现的比较坑的问题。浏览器或者是 webview 缓存 GET 请求。

这个问题主要发生在需要多次以 GET 的方式请求同一个接口。解决的方案也挺简单就是在我们发起的 GET 请求后面加上时间戳。以使用 axios 为例:

5. 打包工具的配置

本来想统一的使用 typescript 插件来编译 jsx 的。因为迁移 preact 原因,要修改全局 pragma。所以编译前端的 jsx 就使用了 babel-5.x 插件,以下是全局的配置文件介绍。

以上的配置文件是开发环境的配置,在页面加载的时候也是对静态文件逐条加载的。

而且页面的加载时间也比较长不符合我们线上的加载静态文件的需求。

紧接着对打包脚本进行优化

这样做最后线上的页面加载时,加载的静态文件(除了图片)只有 3 个。页面的加载时间也保留在 200ms 以内。而所有的 npm 依赖最后的 bundle 文件也只有 80kb 的大小。这个对于现代的前端网络是可以接受的。
w005y

排除非首屏的加载,使用缓存加载页面的。这个时间已经缩短的极小了。

1cg5w

以下是我在一 APP 内打开页面后,每次都使用缓存文件加载的结果。所有的静态文件都使用了本地缓存,http 状态码都是 304

uw5sd

在这个过程中也发现一个问题,就是使用时间戳的方式和使用 hash 戳的方式,缓存静态文件。观察下面的截图发现, 使用时间戳的方式,并不能有效的缓存我们的静态文件,每次进入页面,静态文件都重新发起了请求。因为又没有使用 CDN 加速,这样其实也间接的对我们的服务器造成压力。

f6hkd

迁移 preact

最后就是介绍下迁移 react 到 preact 我都是做了那些工作吧。当然按照官网提供的步骤一步一步走肯定是没有错的。

首先是修改库的引入方式

因为使用了 preact-router。所以路由的配置方式和 react-router 的有些不一样的

第二就是修改编译的打包脚本。按照官网的介绍就是要修改最后编译结果的 jsx 的包裹方式。在前面的关于打包脚本的配置已经介绍过了. 主要就是配置 jsxPragma 属性。

后续的计划

  1. 引入 redux 做状态管理
  2. 因为使用了 preact,它默认是不提供 prop-type 做类型检查的。所以以后准备在项目引入 typescript 编写代码。因为它默认提供了静态类型检查的机制。
  3. 因为 react 的特点。当我们切换页面的时候其实是在不同的 view(或者说是 state)间进行切换。我们并没有重新请求页面服务器。所以页面切换的时候可以做一些类似原生的切换动画。
  4. 将静态文件的加载走 cdn 加速域名。

参考文章:

  1. 如何用 fis3 来开发 React?

转自 http://web.jobbole.com/92436/

分享到:更多 ()