记一次fis3+react开发经历

作者:zhiqiang21

blog.csdn.net/yisuowushinian/article/details/78011330

前言:

虽然说是记录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。所以我的目录结构也相对简单一些。如下:

.

├──components//组件目录

├──containers//组件容器

├──language//语言包目录,为项目做国际化预留的能力

├──node_modules//npm依赖

├──package-lock.json

├──package.json

├──page//页面模块

├──routes//路由模块

├──state//因为没有引入redux但是有一个页面的状态实在太多还是单独为它做了一个文件管理state

├──static//静态文件模块

└──yarn.lock

3.拆分页面

使用react的第一项工作就是要拆分自己页面。把自己的页面拆分成"一块一块"

的组件。所以看下图我的页面结构。

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

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

├──components

│├──Header.jsx

│├──Input.jsx

│├──PassBtn.jsx

│├──SafeCenter.jsx

│├──SafeList.jsx

│├──header.styl

│├──input.styl

│├──passbtn.styl

│├──safecenter.styl

│└──safelist.styl

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

├──containers

│├──BankList.jsx

│├──EditUserInfor.jsx

│├──EditUserInfor.styl

│├──SafeCenterIndex.jsx

│├──VerifyBank.jsx

│├──VerifyRealName.jsx

│├──banklist.styl

│├──verifybank.styl

│└──verifyrealname.styl

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

├──routes

│└──index.jsx

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

export default(

Router history={createBrowserHistory()} >

SafeCenterIndex path="/v4/security/"/>

VerifyRealName path="/v4/security/verifyname"/>

VerifyBank path="/v4/security/verifybank"/>

Router>

);

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

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

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

varobj= {

"aaa": {

"bbb": {

"ccc": {

"ddd": {

"header": "istrue"

}

}

}

}

}

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

obj.aaa.bbb.ccc.ddd.header='isfalse';

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

obj.aaa || obj.aaa.bbb || obj.aaa.bbb.ccc || obj.aaa.bbb.ccc.ddd || obj.aaa.bbb.ccc.ddd.header = 'isfalse'

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

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

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

import *as_form'lodash';

_.set(obj,'aaa.bbb.ccc.ddd.header','isfalse');//更新header的值

varheader =  _.get(obj,'aaa.bbb.ccc.ddd.header')//获取header的值

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

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

import *as_form'lodash';

varinitState = {};

vardeepCloneState = _.cloneDeep(initState);// 我们操作的其实都是这个clone的备份

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

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

axios.get('/v4/xxx/action?v=' + (newDate).getTime())

.then(data => {})

.catch(err => {})

5.打包工具的配置

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

// 定义一个全局的变量目录

constdirList = '{actions,components,constants,routes,containers,page,state,language,reducers,store}';

fis.match('/client/(' + dirList + '/**.{js,es,jsx,ts,tsx})',{

parser: fis.plugin('babel-5.x',{

sourceMaps: false,

optional: ['es7.decorators','es7.classProperties'],

jsxPragma: 'h'// 这里也是最重要的迁移preact后必须加的一个参数

}),

// 页面中显示的url并且加上自定义的v4前缀

url: '/v4${static}/${namespace}/$1$2$3$4$5$6$7$8$9$10',

isJsXLike: true,

// 设置位模块目录最后的编译结果都是会用define包裹

isMod: true

})

// 这里都是为了给静态文件加上v4自定义前缀

.match('/client/({components,containers}/**.styl)',{

url: '/v4${static}/${namespace}/$1',

})

// 这里都是为了给静态文件加上v4自定义前缀

.match('/client/static/({img,js,styl}/**.{png,js,ico,styl})',{

url: '/v4${static}/${namespace}/static/$1$2$3'

})

// 因为使用的stylus做位css的预编译工具,这里的配置是编译stylus的配置

.match('*.styl',{

rExt: '.css',

parser: fis.plugin('stylus',{

sourcemap: false

}),

preprocessor: fis.plugin('autoprefixer',{

'browsers': ['Android >= 2.1','iOS >= 4','ie >= 8','firefox >= 15'],

'cascade': false

})

})

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

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

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

fis.media('prod')

// 压缩css

.match('*.{styl,css}',{

'useHash': true,

'optimizer': fis.plugin('clean-css')

})

.match('/client/node_modules/**.{js,jsx}',{

'isMod': true

})

.match('/client/**.{js,es,jsx,ts,tsx}',{

'preprocessor': [

fis.plugin('js-require-file'),

fis.plugin('js-require-css')

]

})

//合并静态文件

.match('::packager',{

'packager': fis.plugin('deps-pack',{

// 将所有的npm依赖打包成一个文件

'/client/pkg/npm/bundle.js': [

'/client/page/index.js:deps',

'!/client/' + dirList + '/**'

],

//将所有的业务代码打包成一个文件

'/client/pkg/npm/index.js': [

'/client/page/index.js',

'/client/page/index.js:deps'

],

//将所有的css文件打包成一个文件

'/client/pkg/npm/bundle.css': [

'/client/**.{styl,css}',

'!/client/static/**.{styl,css}'

]

})

})

//给所有打包完的文件加前缀

.match('/client/(pkg/npm/**.{js,css})',{

'url': '/v4${static}/${namespace}/$1',

});

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

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

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

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

迁移preact

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

首先是修改库的引入方式

import{h,render,Component}from'preact';

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

import{h,render,Component}from'preact';

import{Router}from'preact-router';

// import {Router} from 'react-router';

import SafeCenterIndex from'../containers/SafeCenterIndex';

import VerifyRealName from'../containers/VerifyRealName';

import VerifyBank from'../containers/VerifyBank';

import{createBrowserHistory}from'history';

export default(

//这里的写法和react-router不一样。

<Router history={createBrowserHistory()} >

<SafeCenterIndex path="/v4/security/"/>

<VerifyRealName path="/v4/security/verifyname"/>

<VerifyBank path="/v4/security/verifybank"/>

</Router>

);

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

fis.match('/client/(' + dirList + '/**.{js,es,jsx,ts,tsx})',{

parser: fis.plugin('babel-5.x',{

sourceMaps: false,

optional: ['es7.decorators','es7.classProperties'],

jsxPragma: 'h'

}),

url: '/v4${static}/${namespace}/$1$2$3$4$5$6$7$8$9$10',

isJsXLike: true,

isMod: true

})

后续的计划

引入redux做状态管理

因为使用了preact,它默认是不提供prop-type做类型检查的。所以以后准备在项目引入typescript编写代码。因为它默认提供了静态类型检查的机制。

因为react的特点。当我们切换页面的时候其实是在不同的view(或者说是state)间进行切换。我们并没有重新请求页面服务器。所以页面切换的时候可以做一些类似原生的切换动画。

将静态文件的加载走cdn加速域名。

参考文章:

如何用 fis3 来开发 React?

觉得本文对你有帮助?请分享给更多人

关注「前端大全」,提升前端技能

「点点赞赏,手留余香」

赞赏

  • 0人赞过
0
0
0
评论 0 请文明上网,理性发言

相关文章

  • React到底是什么?为什么它那么受欢迎?它到底解决了什么问题?答案:React是一个用于构建用户界面的、声明式、组件化的JavaScript库。 JavaScript库?声明式?组件化?不是说好了是小白秘籍吗? 好吧,上面那行字是从官方网站拷过来拼凑的。接下来,让我用另一种方式为你讲解React。很负责任地说,只要你
    天子手游5 5 0 0 条评论
  • 创投圈大小事,你都能尽在掌握 腾讯创业|ID:qqchuangye 【腾讯编者按】布拉德·克里斯平(BradCrispin)原本是客户服务行业的一名从业人员,在30岁之后才开始学习编程,最后成为在线教育平台Udacity的高级工程师。他是怎么做到的?近日,克里斯平在社交网站Medium撰文讲述了自己从零开始学习编程到
    fdgsfg3 7 2 0 条评论
  • FlutterWidget的设计灵感来源于React,是一款原生就立足于响应式的UI框架。本文基于Flutter特点,试图结合闲鱼在Flutter的工程应用来谈下我们对FlutterReact编程范式的思考和践行。 Reactive的诞生谈起UI总会讲到MVC,它出现的时间很早,那时候还没有普及现代GUI广泛使用的事件
    Hi一斤染 7 6 0 条评论
  • 作者|OvieOkeh 译者|王强 这个题目可能有点夸张,但不管怎样Svelte和它的理念就是这样的。如果你还没听说过Svelte的话就去了解一下吧--你会见证一场革命的,它将取得空前的成就(没有给Svelte团队增加压力的意思)。 本文不是Svelte的入门教程。Svelte团队已经做了一份很棒的交互式手把手入门教
    蔡佳佳c 4 0 0 条评论
  • JavaScript每天都在出现大量的框架和工具,而React是除了上次我们提到的Vue和Ember之外另一款比较流行的框架。但因为新的工具每天都在不断的出现,开发者在尝试时总会有些不知所措。因此,当为你的新React项目选择合适的IDE,合适的可视化工具甚至是合适的样式时,你都会有很多选择,你该怎么选择合适的?这是
    雁屋花子smile 5 0 0 条评论
  • React已经火到不行了,相信大家伙儿或多或少的看过或者自己动手实践过一些demo,所以关于一些基础的概念我这里就不再赘述,大家可以在km或者google上搜索"React入门"。网上的大多数demo都是静态渲染的例子,只是玩具,并不能很好的体现实际开发过程。兴趣部落PC版在生产环境采用了React,这里给大家分享一下
    gZT82OQW4zFeN 4 1 0 条评论
  • 但是我们知道,JavaScript作为一个动态语言,你想用静态的方式去分析它是非常复杂一件事情,我们只要稍微在刚才的例子中加入一点动态的写法,这些框架就可能编译失败。 下面是一个用react-reconciler这个包去实现一个迷你ReactDOM的例子,我们需要给ReactReconciler方法传入一个配置,这
    葛启云123n胁 3 1 0 条评论
  • React是最热门的前端技术,这已不是什么秘密。越来越多的大厂,都优先考虑用React做项目,在面试中也经常会考察对React的理解。 React技术是开发Web应用的一把利器。不过在实际工作中,很多前端开发者都存在一个误区:过于关注和强调"最新框架""最新版本",缺乏对前端发展历史的深度了解,也缺少对前端新技术新领域
    心情不好吼力豪 8 6 0 条评论
  • 作者:zhiqiang21 blog.csdn.net/yisuowushinian/article/details/78011330 前言: 虽然说是记录fis3+react的一次开发经历。但是在项目的上线前几天收到公司TC委员会的邮件,因为react的开源协议让找到react的替代方案,并且逐步下线线上的react
    小情绪ZK涡 3 0 0 条评论
  • 导读:如果你正在用React.js或ReactNative来开发用户界面的话,试试这些框架。本文字数:7739,阅读时长大约:9分钟 https://linux.cn/article-13796-1.html 作者:AmitDua 译者:zpl1025 React.js和ReactNative都是用来开发用户界面(U
    顾俸虑凸雇 8 3 0 条评论