最近这些年,随着前端应用技术突飞猛进,产生了很多新的前端框架,当然也引入了数不胜数的前端技术概念,前端不在是早期Web Form的拖拉处理方式,也不再是Ajax+HTML那么简单,随着前端技术的发展,前端的JS越来越重要,也越来越复杂,而为了开发的方便,引入了很多可以对JS+CSS进行编译的框架,而在发布的时候按需编译处理,从而增强了整个前端的开发过程,这些前端的技术包括AngularJS、React、Vue等等,这些前端技术应用框架又囊括了很多相关的技术,包括了MVVM(Model-View-ViewModel)、ES6、Babel、dva、umi、less等技术或概念。前端技术越滚越大,范围也越来越广,大有日新月异的感觉。

1、前端技术的自我回顾和展望

记得在上大学时候,开始玩asp的年代,前端和后端糅合一起的困境;也曾记得WebForm开发的乐趣和无奈,快捷但是很丑很笨重;而现在还在继续做着Ajax + HTML的这种前端的处理,痛并快乐着。技术总是一步步的推进则,但是眼光一旦聚焦在某个技术范畴,日月如梭,抬头间很快就会发现世界又多了新的前端技术,从开始的犹豫和不确信的停留这段时间后,发现整个前端的世界也已经渐成格局,包括Angular、React、Vue等技术应用已经日趋成熟,而且拥有着庞大的拥趸群体,也有着丰富的资源可供学习和了解。

下面是Angular、React、Vue几个技术框架的一些介绍。

AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVC(Model–view–controller)、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。Angular开发在全球开发人员中广泛流行,并被谷歌,福布斯,WhatsApp,Instagram,healthcare.gov和许多财富500强公司等大型组织使用。

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。 由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

Vue.js是讨论最多且发展最快的JavaScript框架之一。它由前谷歌员工Evan You创建,他在担任Google员工时曾在Angular工作过。您可以认为它是成功的,因为它能够使用HTML,CSS和JavaScript构建有吸引力的UI。

这些技术各有优点,很难片面的说明谁优谁劣,它们都各自有自己的生存土壤和大批的拥趸,而我开始选型做前端技术更新的时候,主要看中的是阿里巴巴的Ant-Design开发框架,这个它是使用了React的技术框架,因此也就自然而然的研究学习起React和Ant-Design来,虽然之前对前端的一些技术有所涉猎,但是真正等你想要进入Ant-Design的开发大门的时候,还是感觉自己像进入了一个前端技术的大观园,一个个新概念接踵而来,一种种代码的写法迎面冲击,教程看了几遍还是一头雾水,真的开始怀疑人生了,不过学习新技术还是需要很多平静的心态,调整好,一步一个脚印相信还是有所斩获的,偶尔看到阮一峰的大牛介绍在学习研究React的时候,也曾花了几个月的时候,虽然他的高度难以看齐,但是学习的韧劲和毅力,是值得我们学习的。学习新的东西,从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目(摘自阮一峰笔记)。

2、React的技术学习

接触一些新的东西,就必然需要投入精力来学习掌握。对于学习Ant-Desin,虽然这个框架本身提供了很多教程介绍,但是我们一些技术点,还是需要更细节的学习,首推还是阮一峰的技术日志吧。

1、ECMAScript 6 入门

2、React 入门实例教程

3、Redux 入门教程(一):基本用法

4、Redux 入门教程(二):中间件与异步操作

5、Redux 入门教程(三):React-Redux 的用法

6、Redux 文档基础教程

7、DvaJS快速上手

下面有些内容在学习的时候,掌握的不是很好,摘录并作为一个回顾吧。

模块的 Import 和 Export

import 用于引入模块,export 用于导出模块。

  1. // 引入全部
  2. import dva from 'dva';
  3.  
  4. // 引入部分
  5. import { connect } from 'dva';
  6. import { Link, Route } from 'dva/router';
  7.  
  8. // 引入全部并作为 github 对象
  9. import * as github from './services/github';
  10.  
  11. // 导出默认
  12. export default App;
  13. // 部分导出,需 import { App } from './file'; 引入
  14. export class App extend Component {};

析构赋值

析构赋值让我们从 Object 或 Array 里取部分数据存为变量。

  1. // 对象
  2. const user = { name: 'guanguan', age: 2 };
  3. const { name, age } = user;
  4. console.log(`${name} : ${age}`); // guanguan : 2
  5.  
  6. // 数组
  7. const arr = [1, 2];
  8. const [foo, bar] = arr;
  9. console.log(foo); //

我们也可以析构传入的函数参数。

  1. const add = (state, { payload }) => {
  2. return state.concat(payload);
  3. };
  4.  
  5. //析构时还可以配 alias,让代码更具有语义
  6. const add = (state, { payload: todo }) => {
  7. return state.concat(todo);
  8. };

对象展开运算符(Object Spread Operator)

  1. //可用于组装数组。
  2. const todos = ['Learn dva'];
  3. [...todos, 'Learn antd']; // ['Learn dva', 'Learn antd']
  4.  
  5. //也可用于获取数组的部分项。
  6. const arr = ['a', 'b', 'c'];
  7. const [first, ...rest] = arr;
  8. rest; // ['b', 'c']
  9.  
  10. // With ignore
  11. const [first, , ...rest] = arr;
  12. rest; // ['c']
  13.  
  14. //还可收集函数参数为数组。
  15. function directions(first, ...rest) {
  16. console.log(rest);
  17. }
  18. directions('a', 'b', 'c'); // ['b', 'c'];
  19.  
  20. //代替 apply。
  21. function foo(x, y, z) {}
  22. const args = [1,2,3];
  23.  
  24. // 下面两句效果相同
  25. foo.apply(null, args);
  26. foo(...args);
  27.  
  28. //对于 Object 而言,用于组合成新的 Object
  29. const foo = {
  30. a: 1,
  31. b: 2,
  32. };
  33. const bar = {
  34. b: 3,
  35. c: 2,
  36. };
  37. const d = 4;
  38.  
  39. const ret = { ...foo, ...bar, d }; // { a:1, b:3, c:2, d:4 }

propTypes

JavaScript 是弱类型语言,所以请尽量声明 propTypes 对 props 进行校验,以减少不必要的问题。

  1. function App(props) {
  2. return <div>{props.name}</div>;
  3. }
  4. App.propTypes = {
  5. name: React.PropTypes.string.isRequired,
  6. };

内置的 prop type 有:

  • PropTypes.array
  • PropTypes.bool
  • PropTypes.func
  • PropTypes.number
  • PropTypes.object
  • PropTypes.string

DVA数据流向

数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候可以通过 dispatch 发起一个 action,如果是同步行为会直接通过 Reducers 改变 State ,如果是异步行为(副作用)会先触发 Effects 然后流向 Reducers 最终改变 State。

Reducer和effects

reducer 是一个函数,接受 state 和 action,返回老的或新的 state 。即:(state, action) => state

  1. app.model({
  2. namespace: 'todos',
  3. state: [],
  4. reducers: {
  5. add(state, { payload: todo }) {
  6. return state.concat(todo);
  7. },
  8. remove(state, { payload: id }) {
  9. return state.filter(todo => todo.id !== id);
  10. },
  11. update(state, { payload: updatedTodo }) {
  12. return state.map(todo => {
  13. if (todo.id === updatedTodo.id) {
  14. return { ...todo, ...updatedTodo };
  15. } else {
  16. return todo;
  17. }
  18. });
  19. },
  20. },
  21. };

建议最多一层嵌套,以保持 state 的扁平化,深层嵌套会让 reducer 很难写和难以维护。

  1. app.model({
  2. namespace: 'app',
  3. state: {
  4. todos: [],
  5. loading: false,
  6. },
  7. reducers: {
  8. add(state, { payload: todo }) {
  9. const todos = state.todos.concat(todo);
  10. return { ...state, todos };
  11. },
  12. },
  13. });

effects示例

  1. app.model({
  2. namespace: 'todos',
  3. effects: {
  4. *addRemote({ payload: todo }, { put, call }) {
  5. yield call(addTodo, todo);
  6. yield put({ type: 'add', payload: todo });
  7. },
  8. },
  9. });

put用于触发 action,call用于调用异步逻辑,支持 promise。

异步请求

异步请求基于 whatwg-fetch,API 详见:https://github.com/github/fetch

GET 和 POST

  1. import request from '../util/request';
  2.  
  3. // GET
  4. request('/api/todos');
  5.  
  6. // POST
  7. request('/api/todos', {
  8. method: 'POST',
  9. body: JSON.stringify({ a: 1 }),
  10. });

统一错误处理

假如约定后台返回以下格式时,做统一的错误处理。

  1. {
  2. status: 'error',
  3. message: '',
  4. }

编辑 utils/request.js,加入以下中间件:

  1. function parseErrorMessage({ data }) {
  2. const { status, message } = data;
  3. if (status === 'error') {
  4. throw new Error(message);
  5. }
  6. return { data };
  7. }

然后,这类错误就会走到 onError hook 里。

Subscription

subscriptions 是订阅,用于订阅一个数据源,然后根据需要 dispatch 相应的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。格式为 ({ dispatch, history }) => unsubscribe 。

异步数据初始化

比如:当用户进入 /users 页面时,触发 action users/fetch 加载用户数据。

  1. app.model({
  2. subscriptions: {
  3. setup({ dispatch, history }) {
  4. history.listen(({ pathname }) => {
  5. if (pathname === '/users') {
  6. dispatch({
  7. type: 'users/fetch',
  8. });
  9. }
  10. });
  11. },
  12. },
  13. });
 
react dva 的 connect 与 @connect
 
connect的作用是将组件和models结合在一起。将models中的state绑定到组件的props中。并提供一些额外的功能,譬如dispatch

connect 的使用

connect 方法返回的也是一个 React 组件,通常称为容器组件。因为它是原始 UI 组件的容器,即在外面包了一层 State。

connect 方法传入的第一个参数是 mapStateToProps 函数,该函数需要返回一个对象,用于建立 State 到 Props 的映射关系。

简而言之,connect接收一个函数,返回一个函数。

第一个函数会注入全部的models,你需要返回一个新的对象,挑选该组件所需要的models。

  1. export default connect(({ user, login, global = {}, loading }) => ({
  2. currentUser: user.currentUser,
  3. collapsed: global.collapsed,
  4. fetchingNotices: loading.effects['global/fetchNotices'],
  5. notices: global.notices
  6. }))(BasicLayout);
  7.  
  8. // 简化版
  9. export default connect(
  10. ({ user, login, global = {}, loading }) => {
  11. return {
  12. currentUser: user.currentUser,
  13. collapsed: global.collapsed,
  14. fetchingNotices: loading.effects['global/fetchNotices'],
  15. notices: global.notices
  16. }
  17. }
  18. )(BasicLayout);

@connect的使用

其实只是connect的装饰器、语法糖罢了。

  1. // 将 model 和 component 串联起来
  2. export default connect(({ user, login, global = {}, loading }) => ({
  3. currentUser: user.currentUser,
  4. collapsed: global.collapsed,
  5. fetchingNotices: loading.effects['global/fetchNotices'],
  6. notices: global.notices,
  7. menuData: login.menuData,
  8. redirectData: login.redirectData,
  9. }))(BasicLayout);
  1. // 改为这样(export 的不再是connect,而是class组件本身。),也是可以执行的,但要注意@connect必须放在export default class前面:
  2. // 将 model 和 component 串联起来
  3. @connect(({ user, login, global = {}, loading }) => ({
  4. currentUser: user.currentUser,
  5. collapsed: global.collapsed,
  6. fetchingNotices: loading.effects['global/fetchNotices'],
  7. notices: global.notices,
  8. menuData: login.menuData,
  9. redirectData: login.redirectData,
  10. }))
  11.  
  12. export default class BasicLayout extends React.PureComponent {
  13. // ...
  14. }
export default connect(从 model 的 state 中获取数据)(要将数据绑定到哪个组件) 
 

以上部分内容摘自 https://blog.csdn.net/zhangrui_web/article/details/79651812

2、Ant-Design的框架

这款基于React开发的UI框架,界面非常简洁美观,是阿里巴巴旗下蚂蚁金融服务集团(旗下拥有支付宝、余额宝等产品)所设计的一个前端UI组件库。目前支持了React, 并且有一个对Vue支持的测试版本。

学习和使用Ant-Design,我们可以使用VSCode来对项目代码进行维护和编辑,这样可以在Mac和Window环境同样的开发体验和操作模式,非常方便。

如果需要掌握Ant-Design框架,我们需要了解model,namespace,connect,dispatch,action,reducer ,effect这些概念。

DVA 的 model 对象有几个基本的属性介绍。

  1. namespace:model 的命名空间,只能用字符串。一个大型应用可能包含多个 model,通过namespace区分。
  1. state:当前 model 状态的初始值,表示当前状态。
  1. reducers:用于处理同步操作,可以修改 state,由 action 触发。reducer 是一个纯函数,它接受当前的 state 及一个 action 对象。action 对象里面可以包含数据体(payload)作为入参,需要返回一个新的 state。
  1. effects:用于处理异步操作(例如:与服务端交互)和业务逻辑,也是由 action 触发。但是,它不可以修改 state,要通过触发 action 调用 reducer 实现对 state 的间接操作。
  1. action:action 就是一个普通 JavaScript 对象,是 reducers 及 effects 的触发器,形如{ type: 'add', payload: todo },通过 type 属性可以匹配到具体某个 reducer 或者 effect,payload 属性则是数据体,用于传送给 reducer 或 effect。

整体的数据流向见下图:

在Reducer里面,不要修改传入的 state。 使用 Object.assign() 新建了一个副本。不能这样使用 Object.assign(state, { visibilityFilter: action.filter }),因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。

  1. function todoApp(state = initialState, action) {
  2. switch (action.type) {
  3. case SET_VISIBILITY_FILTER:
  4. return Object.assign({}, state, {
  5. visibilityFilter: action.filter
  6. })
  7. default:
  8. return state
  9. }
  10. }

或者使用使用对象展开运算符(Object Spread Operator)来处理,从而使用 { ...state, ...newState } 达到相同的目的。

  1. reducers: {
  2. save(state, action) {
  3. return {
  4. ...state,
  5. ...action.payload,
  6. };
  7. },
  8. },

在 default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state

每个 reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据。

下面两种合成 reducer 方法完全等价:

  1. const reducer = combineReducers({
  2. a: doSomethingWithA,
  3. b: processB,
  4. c: c
  5. })
  1. function reducer(state = {}, action) {
  2. return {
  3. a: doSomethingWithA(state.a, action),
  4. b: processB(state.b, action),
  5. c: c(state.c, action)
  6. }
  7. }

dva封装了redux,减少很多重复代码比如action reducers 常量等,dva所有的redux操作是放在models目录下,通过namespace作为key,标识不同的模块state,可以给state设置初始数据。

reducers跟传统的react-redux写法一致,所有的操作放在reducers对象内

Effect 被称为副作用,在我们的应用中,最常见的就是异步操作,Effects 的最终流向是通过 Reducers 改变 State

其中上面的effects里面,call, put其实是saga的写法,dva集成了saga,可以参考上图中的saga内容

DVA 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,DVA 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。

DVA 是基于现有应用架构 (redux + react-router + redux-saga 等)的一层轻量封装,没有引入任何新概念,全部代码不到 100 行。

在Ant-Design的Pages/.umi目录里面,有一个initDva.js文件,就是用来统一批量处理 DVA 的引入的,如下所示。

在有 DVA 之前,我们通常会创建 sagas/products.jsreducers/products.js 和 actions/products.js,然后在这些文件之间来回切换。

有了 DVA 后,它最核心的是提供了 app.model 方法,用于把 reducer, initialState, action, saga 封装到一起,这样我们在书写代码的时候,把它主要内容,和加载分离出来。如果建立的Model比较多,每次开始的时候需要加入这一句好像也是挺麻烦的,如果可以自动把这个model批量加入,应该会更好吧,不过不知道是基于什么考量。

关于当前Web前端技术的一些感悟和笔记的更多相关文章

  1. 最受欢迎web前端技术总结

    Web前端技术发展非常快,主流技术的进步.想想刚毕业那会用asp技术.目前,该网站已经非常少见主流应用. 后来的后来J2EE框架.然后SpringMVC声望,然而,最近的各种js框架广泛传播,Html ...

  2. 绝版珍珍藏:web前端技术学习指南

    绝版珍珍藏:web前端技术学习指南 优秀的Web前端开发工程师要在知识体系上既要有广度和深度!应该具备快速学习能力. 前端开发工程师不仅要掌握基本的Web前端开发技术,网站性能优化.SEO和服务器端的 ...

  3. 20151028整理罗列某种开发所包括对技术(技术栈),“较为全面”地表述各种技术大系的图表:系统开发技术栈图、Web前端技术栈图、数据库技术栈图、.NET技术栈图

    ———————————— 我的软件开发生涯 (10年开发经验总结和爆栈人生) 爆栈人生 现在流行说全栈.每种开发都有其相关的技术.您是否觉得难以罗列某种开发所包括对技术(技术栈)呢?   您是否想过: ...

  4. 现代前端技术解析:Web前端技术基础

    ​ 最近几年,越来越多的人投入到前端大军中:时至至今,前端工程师的数量仍然不能满足企业的发展需求:与此同时,互联网应用场景的复杂化提高了对前端工程师能力的要求,一部分初期前端工程师并不能胜任企业的工作 ...

  5. web前端技术社区分享

    web前端技术社区分享 一.国外的前端技术网站:    1. 名称:W3C: 网址:http://www.w3.org/ 理由:前端技术的规范标准几乎都是W3C制定的  2.名称:ECMA 网址:ht ...

  6. 当下较热web前端技术汇总

    Web前段技术发展很快,主流技术日新月异,想想自己刚毕业那会用的asp技术,现在已经很少有主流网站在使用了.再到后来的J2EE框架,然后SpringMVC大行其道,但是最近各种js框架被广为传播,Ht ...

  7. web前端技术与原生技术的竞争, 及未来的发展

    用户界面领域: web技术与原生技术之争 除了浏览器中运行之外, html5的技术也在app领域和移动端的安卓, iOS, 以及桌面端的window, linux以及OS X展开了竞争. 同样属于用户 ...

  8. Web前端技术研究:Css hack技术---令人沮丧的技术

    我最近想好好整理下csshack技术,但是结果很沮丧,下面我将我最初写的笔记和大家分享下. 我在单位整理的研究笔记: 不同的浏览器对某些CSS代码解析会存在一定的差异,因此就会导致不同浏览器下给用户展 ...

  9. web前端技术体系大全

    一.前端技术框架 1.Vue.js 官网:https://cn.vuejs.org/ Vue CLI:https://cli.vuejs.org/ 菜鸟教程:http://www.runoob.com ...

随机推荐

  1. Intellij Idea 无法启动项目的配置坑

    1. run/debug configuration里面,tomcat的deployment点击添加不能自动创建war-explorded包: 方案:删除project libraries,重新mav ...

  2. PHP全栈学习笔记5

    php与mysql数据库,PHP支持很多数据库,与mysql为牛逼组合,mysql数据库的基础知识的掌握是由必要的,要了解如何操作mysql数据库,数据表的方法. 什么是数据库,数据库能做什么,数据库 ...

  3. Oracle AWRSQRPT报告生成和性能分析

    我写的SQL调优专栏:https://blog.csdn.net/u014427391/article/category/8679315 对于局部的,比如某个页面列表sql,我们可以使用Oracle的 ...

  4. 将Python 程序打包成 .exe格式入门

    PyInstaller PyInstaller 是一个十分有用的第三方库,可以用来打包 python 应用程序,打包完的程序就可以在没有安装 Python 解释器的机器上运行了. 它能够在 Windo ...

  5. Linux 虚拟网络设备 veth-pair 详解,看这一篇就够了

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 前面这篇文章介 ...

  6. Java读取excel表,getPhysicalNumberOfCells()和getLastCellNum区别

    excel表存入数据库,发现有时报数组下标越界异常.调试发现用了 getPhysicalNumberOfCells(),这个是用来获取不为空的的列个数. getLastCellNum是获取最后一个不为 ...

  7. docker-swarm建立本地集成开发环境

    在k8s出现之后,docker-swarm使用的人越来越少,但在本地集成开发环境的搭建上,使用它还是比较轻量级的,它比docker-compose最大的好处就是容器之间的共享和服务的治理,你不需要li ...

  8. ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)解决办法

    一,报错原因及分析 mysql的这个报错的原因是mysql服务没有正确启动就是mysqld这个程序. mysql要想运行需要mysql和mysqld两个都启动才行 二,解决办法 右键我的电脑——> ...

  9. Entity Framework 查漏补缺 (二)

    数据加载 如下这样的一个lamda查询语句,不会立马去查询数据库,只有当需要用时去调用(如取某行,取某个字段.聚合),才会去操作数据库,EF中本身的查询方法返回的都是IQueryable接口. 链接: ...

  10. C#线程安全使用(五)

     CancellationToken的多种应用 这是线程安全的最后一篇了,主要介绍CancellationToken的多种应用. 1,ThreadPool直接启动线程,传递CancellationTo ...