react干货
起源:Facebook在建设instagram(一个广告系统项目)的时候,为了很好的处理数据流并且还要考虑好性能方面的问题,开始对市场上的各种前端MVC框架考量,然而并没有看上眼的,于是重新思考前端界面的构建方式,自己开发了一套,果然全球市值靠前的大牛创造力是很强大的。后来发现这套框架蛮好用的,就投入大量的人力物力去继续研究。ReactJs在2013年5月宣布开源。直到现在,react依然在github上是当家花旦一样的存在,star指数遥遥领先。卓越的性能和优点致使国内外很多大公司也都在使用。
愿景:从最开始的简单的展现一个页面,到为今需要复杂的交互来达到良好的用户体验。基于HTML的前端界面开发正变得越来越复杂。本质问题就是如何将庞大的数据及用户交互数据的变更更好的展现给用户界面上。这也是React完全面向此问题的一个解决点,按官网描述的出发点为:用于开发数据不断变化的大型应用程序(Building large applications with data that changes over time)。相比传统型的前端开发,React开辟了一个相当另类的途径,实现了前端界面的高性能高效率开发。
原理:(一些面试官所谓的底层)在Web开发中(react native是react为开发webapp的衍生品)我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是产生巨大性能问题的原因。
React为此引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比(diff算法),得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。
而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从123变为321,又从321变为123,React处理的UI层不会发生任何变化。如果ABCD四个节点,现将A干掉,那么合并的过程仅为B挪到A的位置,C挪至B,D挪至C。
尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,对实际DOM进行操作的仅仅是diff分,这样在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何render的。
Facebook介绍React的视频中聊天应用的例子:
当一条新的消息过来时,传统开发的思路如上图,你的开发过程需要知道哪条数据过来了,如何将新的DOM结点添加到当前DOM树上;
而基于React的开发思路如上图,你永远只需要关心数据整体,两次数据之间的UI如何变化,则完全交给框架去做。
可以看到,使用React大大降低了逻辑复杂性,意味着开发难度降低,可能产生Bug的机会也更少。
小叙:真正学会react是一个漫长的过程,有人说react是MVC框架,我觉得单纯的说react,它顶多算是一个V层。而什么设计模式要具体的根据你的项目而定。就像一个简单的速构脚手架,你都没用模板机制,哪里来的M层,你处理数据的一系列方式能不能称得上C层处理器。先知道MVC > MVP > MVVM的变革,再去理解定义你的项目模式更靠谱。
我们以前操作dom的方式是通过document.getElementById()的方式,这样的过程实际上是先去读取html的dom结构,将结构转换成变量,再进行操作,而reactjs定义了一套变量形式的dom模型,一切操作和换算直接在变量中,这样减少了操作真实dom,和主流MVC模式框架有本质的区别,并不和dom打交道。
优势:
太多了吧,除了以上所说的最重要的性能问题,再例举如下:
react使用xml语法(jsx)快速创建组件的dom结构
组件化开发颠覆了过去的传统的方式,使用react开发的核心就是将页面拆分成若干个组件,从大到小都可称之为一个组件,react认为一个合格的组件也应有如下特征
(1)可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件;
(2)可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个UI场景;
(3)可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护
(4)可测试(Testable):因为每个组件都是独立的,那么对于各个组件分别测试显然要比对于整个UI进行测试容易的多。
单向数据流(Flux思想最大的特点)
react的核心内容也就是数据绑定,所谓数据绑定指的是只要将一些服务端的数据和前端页面绑定好,开发者只关注实现业务就行了,只要服务端数据发生变动,前端数据也变动。
围绕着react又衍生出flux,react-redux,react-router,propTypes,很多中间件甚至自己的GraphQL等等
react有着庞大的生态系统,这也是矗立巅峰的关键,同类产品比不了的重要因素
生命周期及props,state的使用(实际开发的重点学习内容,每个人有自己的理解,建议自己试一下触发顺序及次数,去官网react生命周期或github看源码,深刻理解如何实现写起代码才能少走弯路,得心应手。例如:有些小白一定在componentDidUpdate中没加判断的做过setState,然后浏览器就无限警告setState:一大堆)
初始化阶段:
getDefaultProps 只调用一次,实例之间共享 引用 引用就是说,也就是不同实例操作的都是同一个引用
getInitialState 初始化每个实例特有的状态 每次实例化都会调用
componentWillMount render之前最后一次修改状态的机会 多用于使多个实例显示的不同,在这里修改状态不会导致重新render
render 只能访问输出this.props和this.state
componentDidMount render渲染完成真实dom之后触发 多用于操作真实的dom
运行中阶段:
componentWillReceiveProps 父组件修改自己的属性触发 参数为接受到的属性 可以根据传入的属性来修改自己的状态 修改之后不会重新执行运行中 各种钩子函数
shouldComponentUpdate 组件接收到属性时要不要更新dom,提高性能 返回false会阻止render调用,使组件不更新 大部分时候不会使用,写出来了就必须来return一个
componentWillUpdate 组件要更新前,不能阻止更新 两个参数 第一个是属性,第二个参数为状态 可以查看哪些状态和属性更改了
render 组件更新
componentDidUpdate 组件更新后,可以修改真实dom了
销毁阶段使用的函数:
componentWillUnmount 组件实例销毁前调用 一般用来处理事件绑定之类的东西,释放内存
当你学完后,可以反问自己react的render函数是什么时候执行的?执行了计算是否要重新渲染页面? 渲染前前后后render执行几次?我想这个问题一些做了几年开发的老鸟也会答错。
react的事件对象
事件对象就是事件处理函数传入的形参 就叫做ev吧 这个事件对象是react封装的,为的是各浏览器表现一致,也就是兼容
console.log(e) 里面的都是null
console.log(e.type) 事件类型
因为react做了优化,在不使用的时候就都会是null
事件对象的属性:
如下是我搜集的一些东东,看看以后能否用的上
1:通用属性
- boolean bubbles : 事件是否可以冒泡
- boolean cancelable : 事件是否可以取消
- DOMEventTarget currentTarget :
- boolean defaultPrevented : 事件是否禁止默认行为
- number eventPhase : 事件所处的阶段
- boolean isTrusted : 事件是否可信,可信事件即用户自定义触发的事件,不可信事件即用js代码触发的事件
- DOMEvent nativeEvent 使用原生的浏览器发出的事件对象
- void preventDefault() : 禁止默认行为
- void stopPropagation() : 禁止冒泡
- DOMEventTarget target:
- number timeStamp
- string type
2:不同事件对象特有的属性
键盘事件:
- boolean altKey ; 是否按下alt键
- Number charCode ;按键的编码; 字符编码
- boolean ctrlKey ;是否按下ctrl键
- function getModifierState(key) ; 是否按下辅助按键ctrl,shift
- String key
- Number keyCode; 按键编码;非字符
- String locale ; 本地化的字符串
- Number location ;位置
- boolean metaKey; win键
- boolean repeat ;按键是否重复
- boolean shiftKey; 是否按下shift
- Number which ; 通用化的charCode和keyCode
焦点
- DOMEventTarget relatedTarget :
鼠标事件
- boolean altKey;
- Number button;
- Number buttons;
- Number clientX;
- Number clientY; 当前鼠标所处的坐标, 顶点是浏览器窗口的左上角
- boolean ctrlKey
- function getModifierState(key);
- boolean metaKey;
- Number pageX
- Number pageY; 顶点时html页面的左上角
- DOMEventTarget relatedTarget ;
- Number screenX;
- Number scrrenY; p
- boolean shiftKey;
触摸事件:
- boolean altKey
- DOMTouchList changedTouchs
- boolean ctrlKey
- function getModifierState(Key)
- boolean metaKey
- boolean shiftKey
- DOMTouchList targetTouches
- DOMTouchList touches
UI元素
- Number detail : 滚动的距离
- DOMAbstractView view : 视图
滚动:
- Number deltaMode: 单位
- Number deltaX
- Number deltaY
- Number deltaZ 在坐标轴上对应的位置