之前写过一篇文章,分享了我利用闲暇时间,使用react+redux技术栈重构的百度某产品个人中心页面。您可以参考这里,或者参考github代码仓库地址。
这个工程实例中,我采用了厂内的工程构建工具-fis,并贯穿了react+redux基本思想。
今天这篇文章给大家分享一个更加复杂,但是非常有趣的一个项目-
news early单页应用。
我把这个项目所有代码托管在了我个人github之中,感兴趣的读者可以跟我探讨。
最近我发现,react redux生态圈项目活跃。但是作品质量“良莠不齐”,很多非常热门的项目不仅没有起到“布道”作用,而且在一定程度上“误导”了读者。在这篇文章里面我会有详细说明。当然,我自己也是资历浅显,水平有限。希望大神能够给与斧正。
同时通过这个项目实例和这篇文章,一步一步说明了这个项目开发细节,并且包括了优化手段等内容。希望使大家对于react技术栈,包括:redux数据流框架+react router路由管理+webpack构建工具等,有一个更加清晰深刻的理解。
<b>项目背景</b>
在国外上学和工作期间,能畅通无阻的访问诸如:bbc,cnn,espn,le figaro等新闻媒体是一大便利,也是我个人闲暇时期一个喜好之一。
甚至外出旅游时,在酒店收看这些媒体卫视(尤其cnn)竟然也是放松休闲的一大方式。。。
当然,国内环境对于这些境外媒体显然不是太友好。
基于此,我设计开发了news early项目。
这个项目是一个包括:bbc,cnn,the newyork times等70多个国际知名媒体的即时头条新闻聚合app。 news early is a simple and easy-to-use web app that gathers the headlines currently published on a range of news sources and blogs (70 and counting so far).
整个项目我使用了包括但不限于以下技术栈和构建工具:
1)react ui框架from facebook;
2)jsx模版;
3)redux数据流设计;
4)webpack构建工具;
5)less预处理器;
……
<b>项目设计</b>
整个web app的部分使用体验,我用以下gif图示来呈现:
(请耐心等待gif图加载)
1)页面顶部导航条
包括:侧栏菜单开启按钮和右侧的刷新页面按钮。
2)页面内容头部轮播图
支持自动播放和手势滑动操控。
3)页面主体部分
主体部分是所对应的新闻频道的headlines头条新闻,一般有10-20个items左右。每一个item包含一张新闻图片,新闻导读(abstract)以及新闻发布时间(publish time)。
4)左侧折叠菜单栏
功能用于新闻频道的筛选。
以gif图截取为止,一共接入了:bbc news,bbc sport,cnn,espn,financial times,usa today,mtv news7家国际媒体。
因为我不是搞视觉设计的,也不是做页面交互设计的。我只是一枚码农。所以为了节省时间,整体app的样式上,包括界面颜色等,我参考了卖座网的实现。
<b>项目架构和落地</b>
下面,我为大家介绍一下整个项目的设计构成和开发细节。
<b>数据流状态演示</b>
熟悉redux数据流框架的同学,应该对于store,dispatch,action,reducer,以及中间件等概念比较熟悉。这里不再进行讲解。
这套架构中,最重要的就是数据流的设计。
首先,我们先整体看一下在“切换频道”这个交互发生时,整个项目的数据流向和数据结构的演示:
<b>目录结构</b>
如图所示:
整个项目业务代码部分,我拆分成9个ui组件,1个全局store,一个actions定义文件。
app是开发目录
actions目录集中了全局所有的actions
components目录集中了全局用到的所有ui组件
reducers目录集中了redux架构中的所有reducers
store目录定义全局唯一的store
style目录集中了全局所有组件的样式文件
main.js为全局的入口函数
build是打包后结果目录
index.html是输出页面文件
bundle.js开发目录下脚本文件打包后的产出
img文件定义了app开启时的loading图片
node_modules相信大家不会陌生,这是依赖文件
…
其他配置文件不再一一介绍。
10个组件包括:
appindex: 组件容器
billboardcarousel: 页面轮播图组件
currentchanel: 页面headlines新闻头条组件
homeview: 主体页面
imageplaceholder: 占位图组件
loading: 加载提示组件
navbar :顶部导航组件
sidebar: 侧边栏组件
routerwrap: 路由相关组件
<b></b>
<b>骨架构建</b>
我认为,redux之所以学习曲线陡,很大程度上就在于数据流的贯通上。
“组件触发(dispatch)各种action,单向数据流流向reducer,reducer是一个纯函数(函数式编程思想),接收处理action,返回新的数据,组件进而更新”
这一套理论并不难理解。
但是落实在工程上,尤其要结合react,那就不好做了。即使有人做出来,业务就算可以跑得通,但是相比核心思想,却是背道而驰。社区上我看过很多项目,在写法上不分青红皂白,只要能运行,胡乱设计一通,误导初学者。
比如在整个项目中,存在多个stores这种常见的问题。
那么,为什么不建议存在多个store呢?
答案可以在官方faq中找到。内容较多,如果英文阅读吃力,我大体翻译一下:
熟悉flux原始模型的读者可能了解,flux存在多个stores,每个store都维护了不同层次的数据。这样设计的问题在于,一个store需要等待另外一个store的操作处理。我们redux实现了切分数据层次,避免了这种情况的发生。
仅维持单个store不仅可以使用redux devtools,还能简化数据的持久化及深加工、精简订阅的逻辑处理。
单一store这种方式,我们不用考虑store模块的导入、 redux应用的封装,后期支持服务器渲染也将变得更为简便。
如果上边这段话过于抽象,难以理解的话,那就直接看我的代码实现吧。
定义全局唯一的store:
其中,我使用了redux-thunk作为中间件,用于处理异步action。这样,把异步过程放在action级别解决,对component没有影响。
另外composeenhancers是用于使用redux devtool的设置。
容器组件构建:
其中,我使用了react-redux进行连接。appindex是整个项目唯一的容器组件。进行action的dispatch,以及向下传递props给ui组件(木偶组件)。
如果你还不理解容器组件和ui组件的区别,可以去官方文档学习。这两个概念极其重要,它直接决定你是否能设计出有效且合理的组件架构。
另外,你会发现我使用了react-router进行路由管理。其实整个项目没有必要使用单页路由。这个路由管理的引入,说实话,比较鸡肋。但并不会对项目产生任何影响。我引入他的原因主要有两点。
第一是,后续进行二次开发,考虑到更多的产品迭代的话,使用路由管理是必须的,我们要为长远准备。
另一个原因就是,我从来没用用过,好吧,想尝鲜下。
<b>actions设计</b>
actions当然是必不可少的,我这里选取最重要的“fetchcontents”这个action creator来讨论一下。
初次进入页面时,以及左侧边栏点击选择新闻频道时,都要去拉取数据。比如,app第一次渲染,默认加载“bbc news”新闻频道,页面主体组件在挂载完成后:
向上调用fetchcontents方法,并逐级上传到容器组件。由容器组件进行dispatch:
source表示拉取的新闻频道。此处当然是’bbc-news’。
在actions.js文件中,进行异步action的处理并拉取数据。这里,我使用了最新的fetch api来代替古老的xhr,并利用fetch的promise的理念,封装了一层_get方法,用于ajax异步请求:
对应的action操作:
<b>请求优化</b>
我们知道,这些异步请求的访问速度是很慢的。因此,我采用了几种方法来进行优化。
第一个方法就是加载时的loading美化。
我使用了来自网络的图片占位。
当我把控制台中网络环境人为的模拟为3g时,页面效果如下:
原谅我使用了这么粉嫩少女的加载图。。。
第二个方法其实是一个trick,我的全局图片在初始状态时opacity设置为0,在onload事件触发时设置一个fadein的效果:
这样的一个小技巧最初来自facebook对用户体验的研究。如果您对此有兴趣,可以在我的另外一篇文章中找到相关内容。
web storage来进行优化
因为各大新闻媒体的headlines发布更新是不定时的,这个时间间隔可能较长。而我考虑到用户使用这个web app一般都是在碎片时间中。因此我采用了sessionstorage进行缓存内容。不要问我为什么不使用localstorage…,如果你存在疑问,建议对于web storage的特性再去回炉重修一下。
具体实现方式就是在发送请求时判断sessionstorage是否已经存在此新闻媒体(比如bbc)的数据。如果存在就使用缓存。否则就去进行ajax请求,请求成功的回调函数里进行缓存的种植。
代码部分如下:
当然,有种植缓存,就要有清除缓存。这个按钮我设置在里navbar组件的最右侧:
<b>其他细节</b>
为了使用先进的构建工具的需求,我使用了node最新版本。但是因为工作业务的需要,又要同时保留低版本node环境。为此,我使用了:n这个利器进行node版本管理。
同时,我使用了webpack一系列强大开发功能和构建功能。包括但不限于:
热更新
less编译插件
服务器构建,使用了8088端口
jsx,es6编译
打包发布
彩色日志
…等等,但是我可不是webpack专家。在狼厂,当然使用更多的是fis构建工具。关于fis和webpack的比较,我的网红同事@颜大神有过探索。
<b>总结</b>
这篇文章涉及到了较为前沿的前端开发技术栈。包括了react框架,redux数据流框架以及函数式编程、异步action中间件,fetch异步请求,webpack配置等等。也无形中涉及到了一些成熟产品的设计理念思路。当然这个项目还远没有成熟。在代码仓库中,我会不间断进行更新。
希望本文对大家在各个维度都有所启发。也恳请业界大牛不吝赐教,进行斧正。
最后想跟大家谈一下对于框架和前端学习的一些感受。我记得我刚开始工作,在初次接触前端时,是使用ionic,即angular框架和phonegap开发hybrid移动app。当时我是完全懵b的,只是感觉比利时同事用的超high,6到飞起。每次他用浓重的比利时口音法语给我讲解时,我听的云里雾里,不知所以。
现在想想当时那么菜的原因还是在于自己的js基础不够牢固。当你面对迅速更新换代的前端技术踟蹰茫然时,唯一的捷径就是从基础抓起,从js原型原型链,this,执行环境上下文等等看起。
觉得前端知识有欠缺的读者们,欢迎follow我。最近我会带大家“重读”js经典书籍,以code demo的形式提炼知识点,并会同步到博客和个人github上。
happying code!
原文作者:颜如镜