100steps/Blogs

关于react的一点东西

ljz131 opened this issue · 1 comments

之前没有看群公告,才知道接了分享这个锅,唔也没有什么准备的,就讲讲最近在看的react吧
唔由于本人也是才接触没多久,对与相关术语的接触及英文水平有限,有错误是必然的,欢迎各位大腿指正

react是最近几年很火的框架之一,其衍生品react native也是一个很火的框架(与react并不是一个东西),它期望通过写web app的方法来做到代替native app。这里不得不提一下Web app、Hybrid app与Native app的关系

  • Web app,顾名思义,直接在网页端写成的app,能跨平台使用,但是由于本身限制,各种性能捉鸡,也无法通过硬件进行优化。

  • Native意为本地的,天然的,Native app指原生app,也称本地app。即为平时我们用的大多数手机应用,如波板糖等。特点是其中的大部分UI框架,逻辑结构,数据内容已经写好并包含在整个应用里,用户无需联网也能使用其中的部分内容。

  • Hybrid意为混血的、杂种的,Hybrid app即指混合APP(简单理解就是将web view嵌套进app当中。当然,根据不同的需求我们可以选择不同的嵌套方式,此处关于嵌套方式不做赘述,有兴趣可以自行去了解更多内容)

    native app的开发周期长,维护与更新也相对困难,无法实现跨平台,但是纯粹的web app虽然开发周期快,维护容易,但是也存在问题,即交互感受奇差(主要在于卡顿严重、掉帧明显,得不到良好的反馈,原因在之后进一步说明),无法调用部分设备硬件,无法调用系统通知等等。

    比如native app可以调用GPU进行强制渲染(即使app本身并没有调用其进行渲染),提高流畅度,降低CPU负载,而web app无法做到这一点。所以Hybrid app可以说是顺应潮流而生,通过内嵌web view的形式,得到易于开发维护,但是仍然存在部分缺点。(但是据说web view shell已经支持硬件加速,似乎可以做到提高部分性能的要求,具体程度尚不清楚)

说了这么多,似乎有点跑题了,接下来进入我们的正题-->react(误)

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

与之几乎同知名度与同热度的还有Angular与Vue等一系列产品

AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVVM、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。

Vue.js 是一个用于创建 web 交互界面的库。

从技术角度讲,Vue.js 专注于 MVVM 模型的 ViewModel 层。它通过双向数据绑定把 View 层和 Model 层连接了起来。实际的 DOM 封装和输出格式都被抽象为了 Directives 和 Filters。

从哲学角度讲,Vue 希望通过一个尽量简单的 API 来提供反应式的数据绑定和可组合、复用的视图组件。它不是一个大而全的框架——它只是一个简单灵活的视图层。您可以独立使用它快速开发原型、也可以混合别的库做更多的事情。它同时和诸如 Firebase 这一类的 BaaS 服务有着天然的契合度。

三者可以说各有优劣,在不同的情况下的性能也都不一样。这三者中,Angular的适用领域相对窄一些,React可以拓展到服务端,移动端Native部分,而Vue因为比较轻量(至于多轻因为没具体用过我也说不出来),还能用于业务场景非常轻的页面中。

其中,Angular和Vue均是MVVM架构(我奤、大神和银峰老大之前均有详细说过这个架构,见第一篇分享)。

AngularJS主要考虑的是构建CRUD应用(增加Create、查询Retrieve、更新Update、删除Delete),在以下方面具有一定优势:

  • 构建一个CRUD应用可能用到的全部内容包括:数据绑定、基本模板标识符、表单验证、路由、深度链接、组件重用、依赖注入。
  • 测试方面包括:单元测试、端对端测试、模拟和自动化测试框架。
  • 具有目录布局和测试脚本的种子应用作为起点。

Vue的话更多地是看到是强调它的轻量级,特别是对比起react和angular这两个大而全的框架。

以下为作者 尤雨溪 的原话

合理使用 track-by 的情况下,Vue 甚至可以比 React 更快

使用场景上来说:React 配合严格的 Flux 架构,适合超大规模多人协作的复杂项目。理论上 Vue 配合类似架构也可以胜任这样的用例,但缺少类似 Flux 这样的官方架构。小快灵的项目上,Vue 和 React 的选择更多是开发风格的偏好。对于需要对 DOM 进行很多自定义操作的项目,Vue 的灵活性优于 React。

Vue 和 React 的使用场景和深度有何不同?

以下分别贴两种helloworld的demo,更多demo请自行翻阅官方文档

AngularJS

<!doctype html>
<html ng-app>
    <head>
        <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
    </head>
    <body>
        Hello {{'World'}}!
    </body>
</html>

Vue

  • html部分
<div id="app">
  {{ message }}
</div>
  • JS部分
new Vue({
  el: '#app',
  data: {
    message: 'Hello World!'
  }
})

好了下面开始真正地讲react

在2015年年初的React开发者大会上,React项目经理Tom Occhino进一步阐述React诞生的初衷,在演讲中提到,React最大的价值究竟是什么?是高性能虚拟DOM、服务器端Render、封装过的事件机制、还是完善的错误提示信息?尽管每一点都足以重要。但他指出,其实React最有价值的是声明式的,直观的编程方式。

以上我们已经可以看出React的部分优点:

  1. 高性能虚拟DOM(Virtual DOM)

    Virtual DOM的概念的提出是为了简化对DOM的操作:通过在内存中创建 Virtual DOM元素,利用 Virtual DOM来减少对实际DOM的操作从而提升性能。类似于真实的原生DOM,虚拟DOM也可以通过JavaScript来创建,但这样的代码可读性并不好,于是React发明了JSX,利用HTML语法来创建虚拟DOM。

    那么Virtual DOM到底是如何简化操作,达到优化性能的目的的呢?这就不得不介绍一下它的DOM Diff算法了。

什么是DOM Diff算法

Web界面由DOM树来构成,当其中某一部分发生变化时,其实就是对应的某个DOM节点发生了变化。在React中,构建UI界面的思路是由当前状态决定界面。前后两个状态就对应两套界面,然后由React来比较两个界面的区别,这就需要对DOM树进行Diff算法分析。

即给定任意两棵树,找到最少的转换步骤。但是标准的的Diff算法复杂度需要O(n^3),这显然无法满足性能要求。要达到每次界面都可以整体刷新界面的目的,势必需要对算法进行优化。这看上去非常有难度,然而Facebook工程师却做到了,他们结合Web界面的特点做出了两个简单的假设,使得Diff算法复杂度直接降低到O(n)

  1. 两个相同组件产生类似的DOM结构,不同的组件产生不同的DOM结构;
  2. 对于同一层次的一组子节点,它们可以通过唯一的id进行区分。

算法上的优化是React整个界面Render的基础,事实也证明这两个假设是合理而精确的,保证了整体界面构建的性能。

当在DOM树中的同一位置前后输出了不同类型的节点,React直接删除前面的节点,然后创建并插入新的节点。这正是应用了第一个假设,不同的组件一般会产生不一样的DOM结构,与其浪费时间去比较它们基本上不会等价的DOM结构,还不如完全创建一个新的组件加上去。

  • 其中节点还有一个非常重要的属性key(具有唯一标识作用),可以帮助React定位到正确的节点进行比较,从而大幅减少DOM操作次数,提高了性能。以上demo如果未设置key,对其的操作会是分别删除、新建后再更新A和R节点;在设置了key以后的操作,仅仅是提供4次位置信息更新。

(由于我已经扯了一大堆乱七八糟的东西,所以在此就不举更多例子进行说明。有兴趣的可以去百度更加详细的例子)

React对操作DOM树的算法其实非常简单,那就是两棵DOM树只会对同一层次的节点进行比较,对于不同层的节点,只有简单的创建和删除。

2.编程方式

React使用JSX进行编写,编程**类似于,将整个页面分解成若干个组件,每个组件又可以嵌套若干个子组件。于是一整个页面便被拆分成无数个小组件。组件并不是一个新的概念,它意味着某个独立功能或界面的封装,达到复用、或是业务逻辑分离的目的。

React将用户界面看做简单的状态机器。当组件处于某个状态时,那么就输出这个状态对应的界面。通过这种方式,就很容易去保证界面的一致性。

在React中,你简单的去更新某个组件的状态,然后输出基于新状态的整个界面。React负责以最高效的方式去比较两个界面并更新DOM树。

组件是React中构建用户界面的基本单位。它们和外界的交互除了状态(state)之外,还有就是属性(props)。事实上,状态更多的是一个组件内部去自己维护,而属性则由外部在初始化这个组件时传递进来(一般是组件需要管理的数据)。React认为属性应该是只读的,一旦赋值过去后就不应该变化。

同时之前有提到过Angular和Vue使用的是MVVM方式,而React走的是另外一个流派,就是所谓的函数式。在这个里面,推崇的是单向数据流:给定原始界面(或数据),施加一个变化,就能推导出另外一个状态(界面或者数据的更新)。这就又涉及到另一样东西,Flux

Flux并不是什么非常复杂的东西,它仅仅是定义了一种单向数据流的方式,以此解决传统MVC框架中有可能出现的连锁更新现象。

在传统MVC框架中,通常使用双向绑定的方式来将Model的数据展现到View。当Model中的数据发生变化时,一个或多个View会发生变化;当View接受了用户输入时,Model中的数据则会发生变化。在实际的应用中,当一个Model中的数据发生变化时,也有可能另一个相关的Model中的数据会被同步更新。这样,很容易出现的一个现象就是连锁更新(Cascading Update),Model可以更新Model,Model可以更新View,View也可以更新Model。你很难去推断一个界面的变化究竟是由哪个局部的功能代码引起。

在MVC中,数据如何处理通常由Controller来完成,在Controller中实现大部分的业务逻辑来处理数据。而现在则被Flux清晰的定义在Store或者Action Creators中。

在Flux中,View完全是Store的展现形式,Store的更新则完全由Action触发。得益于React的View每次更新都是整体刷新的思路,我们可以完全不必关心Store的变化细节,只需要监听Store的onChange事件,每次变化都触发View的re-render,进行相应的更新。

那么Dispatcher和Action又是什么呢?简单来说,当View接受了用户的输入之后,它通过Dispatcher来分发一个特定的Action,而对应的Action处理函数会负责去更新Store。

说到这,那便不得不说一下最常与React一同提起的Redux

Redux是一种类Flux实现,他关注的重点是就是如何管理state。有必要强调的一点是,Redux 和 React 是没有必然关系的,Redux 用于管理 state,与具体的 View 框架无关(而React恰好是只做View的)。但是Redux特别适合React这种通过状态state来更新view的框架。

在React的思路中,UI就是一个状态机,每个确定的状态对应着一个确定的界面。对于一个小的组件,它的状态可能是在其内部进行维护;而对于多个组件组成的应用程序,如果某些状态需要在组件之间进行共享,则可以将这部分状态放到Store中进行维护。

其中state 可能包括:服务端的响应数据、本地对响应数据的缓存、本地创建的数据(比如,表单数据)以及一些 UI 的状态信息(比如,路由、选中的 tab、是否显示下拉列表、页码控制等等)。

需要强调的是,Redux只是类Flux实现,所以与上文中的Flux必定会有不同之处。以下是两者的流程图对比

我们可以看到其中与Flux不同的是Middleware、Store和Reducers。

  • Action 可以理解为应用向 Store 传递的数据信息(一般为用户交互信息)。
  • Reducer 实际上就是一个函数:(previousState, action) => newState。用来执行根据指定 action 来更新 state 的逻辑。
  • Middleware 其实就是高阶函数,作用于 dispatch 返回一个新的 dispatch(附加了该中间件功能)。可以形式化为:newDispatch = middleware1(middleware2(...(dispatch)...))

最后稍微再提一下JSX

  • JSX与JS并不是一样东西,并且二者并不兼容。JSX看上去很像模板语言,但其本质是通过代码来构建界面,这使得我们不再需要掌握一门新的语言就可以直观的去定义用户界面。JSX的语法和XML语法类似,可以定义属性以及子元素。唯一特殊的是可以用大括号来加入JavaScript表达式。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello React!</title>
    <script src="build/react.js"></script>
    <script src="build/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
      ReactDOM.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
  </body>
</html>

好了由于自己对react的了解也仅仅停留在看文档阶段,并没有大量使用过,对其认知也仅仅停留在看过的各种文章上,所以我的分享差不多就到这里了。以下是我在查阅资料的时候,看过的一些作者提到的我们对React的认知容易进入误区的地方

  • React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式;
  • React的服务器端Render能力只能算是一个锦上添花的功能,并不是其核心出发点,事实上React官方站点几乎没有提及其在服务器端的应用;
  • 有人拿React和Web Component相提并论,但两者并不是完全的竞争关系,你完全可以用React去开发一个真正的Web Component;
  • React不是一个新的模板语言,JSX只是一个表象,没有JSX的React也能工作。
  • React 从来没有说过 “React 比原生操作 DOM 快”。React 的基本思维模式是每次有变动就整个重新渲染整个应用。如果没有 Virtual DOM,简单来想就是直接重置 innerHTML。那我们为什么要有Virtual DOM呢? Virtual DOM 的计算量里面,只有 js 计算和界面大小相关,DOM 操作是和数据的变动量相关的。和 DOM 操作比起来,js 计算是极其便宜的,这才是为什么要有 Virtual DOM。它保证了:
    1. 不管你的数据变化多少,每次重绘的性能都可以接受;
    2. 你依然可以用类似 innerHTML 的思路去写你的应用。

参考链接:
一看就懂的ReactJs入门教程
React官方文档
聊聊Web App、Hybrid App与Native App的设计差异
浅谈Hybrid技术的设计与实现
网上都说操作真实 DOM 慢,但测试结果却比 React 更快,为什么?-知乎
react.js,angular.js,vue.js学习哪个好?-知乎
vue、react和angular 2.x谁是2016年的主流?-知乎
颠覆式前端UI开发框架:React
深入浅出react系列
Redux核心概念
深入理解React、Redux
Redux 介绍
不止是UI:React的使用场景探索

文章信息量很大,不止是“一点东西”了哈