React入门学习

为了得到更好的阅读体验,请访问原地址: 传送门

1、React 简介


React 是什么

React 是一个起源于 Facebook 的内部项目,由于当时 Facebook 对于市场上全部的 JavaScript MVC 框架都不太满意,因此索性就本身写了一套,用来架设 Instagram。作出来以后,发现这套东西还蛮好用的,因而就在 2013 年 5 月开源了html

在这里咱们须要稍微注意一下 库(Library)框架(Framework) 的区别,React 自己是一个用于构建用户界面的 JavaScript 库,而咱们平时所说的 React 框架实际上是指的是 React/ React-router 和 React-redux 的结合体,库和框架的本质区别体如今于控制权:前端

  • 「库」是一个封装好的特定的集合,提供给开发者使用,并且是特定于某一方面的集合(方法和函数),库没有控制权,控制权彻底在于使用者自己;
  • 「框架」顾名思义是一套架构,会基于自身的特色向用户提供一套比较完整的解决方案,若是使用者选定了一套框架,那么就须要根据框架自己作出必定的适应。

为何使用 React?

这是一个很是有趣的问题,也让我困惑和苦恼。在笔者还在学校的时候尝试用 Vue 搭建了一套简单的博客系统,学习曲线平滑,让只会一些基础 HTML/ CSS 代码的我经过一段时间学习就可以上手了,可是学习 React 以来,进展变得相对缓慢.. 一部分缘由是由于 React 创新性的开发模式以及让我感到无所适从的 JSX 语法(菜才是原罪)。react

Vue 做者尤雨溪在知乎上回答「Vue 和 React 的优势分别是什么?」这个问题的时候提到 :git

这里我能够大方地认可,若是多年之后要论历史地位,React 确定是高于 Vue 的。事实上,我做为一个开发者,也是由衷地佩服 Jordan Walke, Sebastian Markbage 这样的,能从开发模式层面上提出突破性的新方向的人。

React 从一开始的定位就是提出 UI 开发的新思路。当年 Pete Hunt 最开始推广 React 的时候的一句口号就叫 "Rethinking Best Practices",这样的定位使得 React 打开了一些全新的思路,吸引了一群喜欢折腾的早期核心用户,并在这个基础上经过社区迭代孵化出了许多今天被 React 开发者看成常识的 pattern。这是 React 伟大的地方,Vue 里面也有不少地方是直接受到了 React 的启发。React 敢作这样的尝试,是由于它是 Facebook。这样的体量的公司,在 infrastructure 层面得到质的提高,收益是巨大的,并且 Facebook 的工程师们足够聪明又要靠工资吃饭,改变他/她们的习惯并非什么问题。而对外推广,则是一种大公司才有的 “改变业界” 的底气。github

相比「为何使用 React?」的理由,称赞 React 的却是明显更多一些(React 确实是突破性的开发模式)。算法

是由于 React 组件化的思想吗?不是。我以为这跟多少跟微服务化之类的概念有点儿相似,这是属于一个时代对于计算机工程的思想进步,是对于团队协做提出的新一种成熟的解决方案,也是必然的一种趋势。当前流行的无论是 Angular/ Vue 仍是 React,都自然的支持着组件化的概念。shell

那是由于 React 性能出众吗?我想也不是。或许 React 刚出世时由于其独特高效的虚拟 DOM 设计,可以在前端江湖中平步青云,可是如今前端技术都主键地趋于成熟(我也不懂,我乱说的..),从不少地方的对比数据中,都可以看获得其实 React 与其余框架的性能差别并非特别大。而且体如今平时的开发中,这样对比不明显的速度差别,根本没有多大的用处。编程

还看到一种观点,说 React 适用于构建大型的项目。从我并很少的了解中,我知道 React 体系中自然有着许多的约束,以及一些不成文的约定,这就好像是 SpringBoot 中默认提供给使用者的一些姿式,自然就有很强的工程性,加上一些约定俗成的代码风格 or 归约,这就使得 Java 很适合一些大型的团队项目。但能不能开发大型的项目历来都是取决于人,而不是采用了哪一种框架。redux

因此比较令我信服的理由是(我乱猜的):像 Java 同样,React 体系足够成熟,社区也很是活跃,你遇到的问题很容易在网络上找到答案,而且也有一些成熟的实践 or 轮子用以解决各类各样的问题。并且 React 还有一个比较特别的特性是:你可以比较无痛地使用 React Native 开发原生移动应用。数组

2、React 核心概念


虚拟 DOM(Vitural Document Object Model)

要理解这个「虚拟 DOM」的概念,首先咱们就须要知道什么是「DOM」。咱们先暂时忘掉什么网页之类的,咱们想象如今咱们须要编写程序来对下列的 Markdown 文档进行改变应该怎么作:

# Title
## subtitle - 1
content - 1
## subtitle - 2
content - 2

好比我如今就想要 content - 2 的内容进行改变,那么我就须要一行一行的不断遍历直到最后遍历到它才能进行操做,对内容改变的操做都差很少,因此若是我想对这个查找的操做进行优化,最简单的想法就是把它树化以减小高度,增长效率。

DOM 的概念

DOM 是英文 Document Object Model 的缩写,即文档对象模型。它是一种跨平台的、独立于编程语言的 API,它把 HTML、XHTML 或 XML 文档都当作一个树结构,而每一个节点视为一个对象,这些对象能够被编程语言操做,进而改变文档的结构,映射到文档的显示。DOM 最开始的时候是和 JavaScript 交织在一块儿的,只是后来它们最终演变成了两个独立的实体。DOM 被设计成与特定编程语言相独立,尽管绝大部分时候咱们都是使用 JavaScript 来操做,但其实其余的语言同样能够(如 Python)。

假若有这么一段 HTML 代码:

<html>
  <head>
    <title>文档标题</title>
  </head>
  
  <body>
    <a href="">连接</a>
    <h1>标题</h1>
  </body>
</html>

那么它最终就应该会是下面这棵树同样的结构:

这里不对 DOM 节点的类型啊方法之类的进行讨论,咱们只须要对 DOM 有一个大体的概念就行了。

浏览器渲染 DOM 的流程

咱们能够简单了解一下浏览器渲染 DOM 的流程:

  1. 解析 HTML 创建 DOM 树;
  2. 解析 CSS,并结合 DOM 树造成 Reander 树;
  3. 布局 Render 树(Layout/ reflow),肯定各节点的尺寸、位置等信息;
  4. 绘制 Render 树(Paint),绘制页面像素信息;
  5. 浏览器将各层信息发给 GPU,GPU 会将各层合成(Composite),显示在屏幕上;

操做 DOM 为何慢

其实严格来讲,单纯的操做 DOM 并不慢,说它慢是带有必定条件的。

想象在一次事件循环中屡次操做 DOM 时,有时但愿 JS 代码中能马上获取最新的 DOM 节点信息,这时浏览器不得不挂起 JS 引擎,转而调用 DOM 引擎,计算渲染出最新的 DOM,以此来获取最新的 DOM 节点信息,接着再从新激活 JS 引擎 继续后续的操做。

能够预见,上述操做不只须要屡次进行引擎的切换,还须要屡次计算布局,从新绘制 DOM。事实上paint是一个耗时的过程,然而layout是一个更耗时的过程,咱们没法肯定layout必定是自上而下或是自下而上进行的,甚至一次layout会牵涉到整个文档布局的从新计算。

可是layout是确定没法避免的,因此咱们主要是要最小化layout的次数。

因此,下降引擎切换频率、减少 DOM 变动规模才是 DOM 性能优化方案的关键!

Virtual DOM 算法步骤

虚拟 DOM 正是解决了上述问题,它的本质就是用 JS 对象来模拟出咱们真实的 DOM 树,它的算法大体以下:

  1. 用 JavaScript 对象映射造成 DOM 树的结构,而后用这个树构建一个真正的 DOM 树,插到文档当中;
  2. 当状态变动的时候,从新构造一棵新的对象树,而后用新的树和旧的树进行比较(Diff 算法),记录两棵树差别;
  3. 把第二步中所记录的差别应用到步骤一所构建的真正的 DOM 树上,视图就更新。

虚拟 DOM 和真实 DOM 的区别

咱们由此能够对比出二者的不一样:

  1. 改变多个状态,影响多个节点布局时,只是频繁的修改了内存中的 JS 对象,而后一次性比较并修改真实 DOM 中须要改的部分,最后在真实 DOM 中进行排版与重绘,减小过多 DOM 节点排版与重绘损耗;
  2. 真实 DOM 频繁排版与重绘的效率是至关低的;
  3. 虚拟 DOM 有效下降大面积(真实 DOM 节点)的重绘与排版,由于最终与真实 DOM 比较差别,能够只渲染局部(同2);

使用虚拟DOM的损耗计算:

总损耗 = 虚拟DOM增删改 + (与Diff算法效率有关)真实DOM差别增删改 + (较少的节点)排版与重绘

直接使用真实DOM的损耗计算:

总损耗 = 真实DOM彻底增删改 + (可能较多的节点)排版与重绘

Diff 算法

虚拟 DOM 的核心在于 Diff,它自动帮你计算那些应该调整的,而后只修改应该被调整的区域,省下的不是运行速度这种 "小速度",而是开发速度/ 维护速度/ 逻辑简练程度等 "整体速度"。

但虚拟 DOM 快也是在相对条件下的,这里引用 @尤雨溪大大在知乎问题《网上都说操做真实 DOM 慢,但测试结果却比 React 更快,为何?》上回答的一句话吧:

不要天真地觉得 Virtual DOM 就是快,diff 不是免费的,batching 么 MVVM 也能作,并且最终 patch 的时候还不是要用原生 API。在我看来 Virtual DOM 真正的价值历来都不是性能,而是它 1) 为函数式的 UI 编程方式打开了大门;2) 能够渲染到 DOM 之外的 backend,好比 ReactNative。

Diff 大体能够分为三种类型:

  • Tree Diff: 新旧两棵 DOM 树,逐层对比的过程,就是 Tree Diff,当整颗DOM逐层对比完毕,则全部须要被按需更新的元素,必然可以找到;
  • Component Diff: 在进行 Tree Diff 的时候,每一层中,组件级别的对比,叫作 Component Diff:

    • 若是对比先后,组件的类型相同,则暂时认为此组件不须要被更新;
    • 若是对比先后,组件类型不一样,则须要移除旧组件,建立新组件,并追加到页面上;
  • Element Diff: 在进行组件对比的时候,若是两个组件类型相同,则须要进行元素级别的对比,这叫作 Element Diff;

3、Hello World


使用 React 的网页源码,结构大体以下(能够直接运行):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Hello React!</title>
    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.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>

上面代码有两个地方须要注意。首先,最后一个 <script> 标签的 type 属性为 text/babel 。这是由于 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel"

其次,上面代码一共用了三个库: react.jsreact-dom.jsBrowser.js ,它们必须首先加载。其中,react.js是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,Browser.js 的做用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。

$ babel src --out-dir build

上面命令能够将 src 子目录的 js 文件进行语法转换,转码后的文件所有放在 build 子目录。

ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('example')
);

上面代码将一个 h1 标题,插入 example 节点,运行结果以下:

JSX 语法

上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它容许 HTML 与 JavaScript 的混写。咱们先来看如下一段代码:

const element = <h1>Hello, world!</h1>;

与浏览器的 DOM 元素不一样,React 当中的元素事实上是普通的对象,React DOM 能够确保 浏览器 DOM 的数据内容与 React 元素保持一致。要将 React 元素渲染到根 DOM 节点中,咱们经过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:

var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));

JSX 看起来相似 HTML ,你也能够在上面代码中嵌套多个 HTML 标签,可是须要使用一个 div 元素包裹它。

JavaScript 表达式

咱们能够在 JSX 中使用 JavaScript 表达式。表达式写在花括号 {} 中。实例以下:

ReactDOM.render(
    <div>
      <h1>{1+1}</h1>
    </div>
    ,
    document.getElementById('example')
);

在 JSX 中不能使用 if else 语句,但可使用 conditional (三元运算) 表达式来替代。如下实例中若是变量 i 等于 1 浏览器将输出 true, 若是修改 i 的值,则会输出 false.

ReactDOM.render(
    <div>
      <h1>{i == 1 ? 'True!' : 'False'}</h1>
    </div>
    ,
    document.getElementById('example')
);

样式

React 推荐使用内联样式。咱们可使用 camelCase 语法来设置内联样式. React 会在指定元素数字后自动添加 px 。如下实例演示了为 h1 元素添加 myStyle 内联样式:

var myStyle = {
    fontSize: 100,
    color: '#FF0000'
};
ReactDOM.render(
    <h1 style = {myStyle}>菜鸟教程</h1>,
    document.getElementById('example')
);

注释

注释须要写在花括号中,实例以下:

ReactDOM.render(
    <div>
    <h1>菜鸟教程</h1>
    {/*注释...*/}
     </div>,
    document.getElementById('example')
);

数组

JSX 容许在模板中插入数组,数组会自动展开全部成员:

var arr = [
  <h1>菜鸟教程</h1>,
  <h2>学的不只是技术,更是梦想!</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

参考资料


  1. http://www.ruanyifeng.com/blog/2015/03/react.html - React 入门实例教程 - 阮一峰
  2. https://www.jianshu.com/p/60100985dd7f - 前端框架与库的区别
  3. https://www.zhihu.com/questio... - Vue 和 React 的优势分别是什么?
  4. https://zhuanlan.zhihu.com/p/... - 你真的理解 DOM 了吗?
  5. https://developer.mozilla.org... - DOM 概述
  6. https://blog.huteming.site/po... - 为何说虚拟DOM更快

按照惯例黏一个尾巴:

欢迎转载,转载请注明出处!
独立域名博客:wmyskxz.com
简书ID: @我没有三颗心脏
github: wmyskxz
欢迎关注公众微信号:wmyskxz
分享本身的学习 & 学习资料 & 生活
想要交流的朋友也能够加qq群:3382693

本文由博客一文多发平台 OpenWrite 发布!
相关文章
相关标签/搜索