React入门学习
<blockquote><p>为了获得更好的阅读体验,请访问原地址:传送门</p>
</blockquote>
<p><img src="https://img2018.cnblogs.com/blog/1120515/201910/1120515-20191015234042416-1086409508.png" alt="" loading="lazy"></p>
<h1 id="一react-简介">一、React 简介</h1>
<hr>
<h2 id="react-是什么">React 是什么</h2>
<p>React 是一个起源于 Facebook 的内部项目,因为当时 Facebook 对于市场上所有的 JavaScript MVC 框架都不太满意,所以索性就自己写了一套,用来架设 Instagram。做出来之后,发现这套东西还蛮好用的,于是就在 <strong>2013 年 5 月开源了</strong>。</p>
<p>在这里我们需要稍微注意一下 <strong>库(Library)</strong> 和 <strong>框架(Framework)</strong> 的区别,<strong>React 本身是一个用于构建用户界面的 JavaScript 库</strong>,而我们平时所说的 React 框架其实是指的是 React/ React-router 和 React-redux 的结合体,库和框架的本质区别体现在于控制权:</p>
<p><img src="https://img2018.cnblogs.com/blog/1120515/201910/1120515-20191015234042674-1715539722.png" alt="" loading="lazy"></p>
<ul>
<li>「库」是一个封装好的特定的集合,提供给开发者使用,而且是特定于某一方面的集合(方法和函数),库没有控制权,控制权完全在于使用者本身;</li>
<li>「框架」顾名思义是一套架构,会基于自身的特点向用户提供一套比较完整的解决方案,如果使用者选定了一套框架,那么就需要根据框架本身做出一定的适应。</li>
</ul>
<h2 id="为什么使用-react">为什么使用 React?</h2>
<p>这是一个非常有趣的问题,也让我困惑和苦恼。在笔者还在学校的时候尝试用 Vue 搭建了一套简单的博客系统,学习曲线平滑,让只会一些基础 HTML/ CSS 代码的我通过一段时间学习就能够上手了,但是学习 React 以来,进展变得相对缓慢.. 一部分原因是因为 React 创新性的开发模式以及让我感到无所适从的 JSX 语法(菜才是原罪)。</p>
<p>Vue 作者尤雨溪在知乎上回答「Vue 和 React 的优点分别是什么?」这个问题的时候提到 :</p>
<blockquote>
<p>这里我可以大方地承认,如果多年以后要论历史地位,React 肯定是高于 Vue 的。事实上,我作为一个开发者,也是由衷地佩服 Jordan Walke, Sebastian Markbage 这样的,能从开发模式层面上提出突破性的新方向的人。</p>
<p>React 从一开始的定位就是提出 UI 开发的新思路。当年 Pete Hunt 最开始推广 React 的时候的一句口号就叫 "Rethinking Best Practices",这样的定位使得 React 打开了一些全新的思路,吸引了一群喜欢折腾的早期核心用户,并在这个基础上通过社区迭代孵化出了许多今天被 React 开发者当作常识的 pattern。这是 React 伟大的地方,Vue 里面也有很多地方是直接受到了 React 的启发。React 敢做这样的尝试,是因为它是 Facebook。这样的体量的公司,在 infrastructure 层面获得质的提升,收益是巨大的,而且 Facebook 的工程师们足够聪明又要靠工资吃饭,改变他/她们的习惯并不是什么问题。而对外推广,则是一种大公司才有的 “改变业界” 的底气。</p>
</blockquote>
<p>相比「为什么使用 React?」的理由,称赞 React 的倒是明显更多一些(React 确实是突破性的开发模式)。</p>
<p>是因为 React 组件化的思想吗?不是。我觉得这跟多少跟微服务化之类的概念有点儿类似,这是属于一个时代对于计算机工程的思想进步,是对于团队协作提出的新一种成熟的解决方案,也是必然的一种趋势。当前流行的不管是 Angular/ Vue 还是 React,都天然的支持着组件化的概念。</p>
<p>那是因为 React 性能出众吗?我想也不是。或许 React 刚出世时因为其独特高效的虚拟 DOM 设计,能够在前端江湖中平步青云,但是现在前端技术都主键地趋于成熟(我也不懂,我乱说的..),从很多地方的对比数据中,都能够看得到其实 React 与其他框架的性能差异并不是特别大。并且体现在平时的开发中,这样对比不明显的速度差异,根本没有多大的用处。</p>
<p>还看到一种观点,说 React 适用于构建大型的项目。从我并不多的了解中,我知道 React 体系中天然有着许多的约束,以及一些不成文的约定,这就好像是 SpringBoot 中默认提供给使用者的一些姿势,天然就有很强的工程性,加上一些约定俗成的代码风格 or 归约,这就使得 Java 很适合一些大型的团队项目。但能不能开发大型的项目从来都是取决于人,而不是采用了哪种框架。</p>
<p>所以比较令我信服的理由是(我乱猜的):像 Java 一样,React 体系足够成熟,社区也非常活跃,你遇到的问题很容易在网络上找到答案,并且也有一些成熟的实践 or 轮子用以解决各种各样的问题。而且 React 还有一个比较特别的特性是:你能够比较无痛地使用 React Native 开发原生移动应用。</p>
<h1 id="二react-核心概念">二、React 核心概念</h1>
<hr>
<h2 id="虚拟-domvitural-document-object-model">虚拟 DOM(Vitural Document Object Model)</h2>
<p>要理解这个「虚拟 DOM」的概念,首先我们就需要知道什么是「DOM」。我们先暂时忘掉什么网页之类的,我们想象现在我们需要编写程序来对下列的 Markdown 文档进行改变应该怎么做:</p>
<pre><code class="language-markdown"># Title
## subtitle - 1
content - 1
## subtitle - 2
content - 2
</code></pre>
<p>比如我现在就想要 <code>content - 2</code> 的内容进行改变,那么我就需要一行一行的不断遍历直到最后遍历到它才能进行操作,对内容改变的操作都差不多,所以如果我想对这个查找的操作进行优化,最简单的想法就是把它树化以减少高度,增加效率。</p>
<h3 id="dom-的概念">DOM 的概念</h3>
<p><strong>DOM</strong> 是英文 Document Object Model 的缩写,即文档对象模型。它是一种跨平台的、独立于编程语言的 API,它把 HTML、XHTML 或 XML 文档都当做一个树结构,而每个节点视为一个对象,这些对象可以被编程语言操作,进而改变文档的结构,映射到文档的显示。DOM 最开始的时候是和 JavaScript 交织在一起的,只是后来它们最终演变成了两个独立的实体。DOM 被设计成与特定编程语言相独立,尽管绝大部分时候我们都是使用 JavaScript 来操作,但其实其他的语言一样可以(如 Python)。</p>
<p>假如有这么一段 HTML 代码:</p>
<pre><code class="language-html"><html>
<head>
<title>文档标题</title>
</head>
<body>
<a href="">链接</a>
<h1>标题</h1>
</body>
</html>
</code></pre>
<p>那么它最终就应该会是下面这棵树一样的结构:</p>
<p><img src="https://img2018.cnblogs.com/blog/1120515/201910/1120515-20191015234042977-1930873135.png" alt="" loading="lazy"></p>
<p>这里不对 DOM 节点的类型啊方法之类的进行讨论,我们只需要对 DOM 有一个大致的概念就好了。</p>
<h3 id="浏览器渲染-dom-的流程">浏览器渲染 DOM 的流程</h3>
<p><strong>我们可以简单了解一下浏览器渲染 DOM 的流程:</strong></p>
<ol>
<li>解析 HTML 建立 DOM 树;</li>
<li>解析 CSS,并结合 DOM 树形成 Reander 树;</li>
<li>布局 Render 树(Layout/ reflow),确定各节点的尺寸、位置等信息;</li>
<li>绘制 Render 树(Paint),绘制页面像素信息;</li>
<li>浏览器将各层信息发给 GPU,GPU 会将各层合成(Composite),显示在屏幕上;</li>
</ol>
<h3 id="操作-dom-为什么慢">操作 DOM 为什么慢</h3>
<p><strong>其实严格来说,单纯的操作 DOM 并不慢,说它慢是带有一定条件的。</strong></p>
<p>想象在一次事件循环中多次操作 DOM 时,有时希望 JS 代码中能立刻获取最新的 DOM 节点信息,这时浏览器不得不挂起 JS 引擎,转而调用 DOM 引擎,计算渲染出最新的 DOM,以此来获取最新的 DOM 节点信息,接着再重新激活 JS 引擎 继续后续的操作。</p>
<p>可以预见,上述操作不仅需要多次进行引擎的切换,还需要多次计算布局,重新绘制 DOM。事实上<code>paint</code>是一个耗时的过程,然而<code>layout</code>是一个更耗时的过程,我们无法确定<code>layout</code>一定是自上而下或是自下而上进行的,甚至一次<code>layout</code>会牵涉到整个文档布局的重新计算。</p>
<p>但是<code>layout</code>是肯定无法避免的,所以我们主要是要最小化<code>layout</code>的次数。</p>
<p><strong>所以,降低引擎切换频率、减小 DOM 变更规模才是 DOM 性能优化方案的关键!</strong></p>
<h3 id="virtual-dom-算法步骤">Virtual DOM 算法步骤</h3>
<p>虚拟 DOM 正是解决了上述问题,<strong>它的本质就是用 JS 对象来模拟出我们真实的 DOM 树</strong>,它的算法大致如下:</p>
<ol>
<li>用 JavaScript 对象映射形成 DOM 树的结构,然后用这个树构建一个真正的 DOM 树,插到文档当中;</li>
<li>当状态变更的时候,重新构造一棵新的对象树,然后用新的树和旧的树进行比较(Diff 算法),记录两棵树差异;</li>
<li>把第二步中所记录的差异应用到步骤一所构建的真正的 DOM 树上,视图就更新。</li>
</ol>
<h3 id="虚拟-dom-和真实-dom-的区别">虚拟 DOM 和真实 DOM 的区别</h3>
<p>我们由此可以对比出两者的不同:</p>
<ol>
<li>改变多个状态,影响多个节点布局时,只是频繁的修改了内存中的 JS 对象,然后一次性比较并修改真实 DOM 中需要改的部分,最后在真实 DOM 中进行排版与重绘,减少过多 DOM 节点排版与重绘损耗;</li>
<li>真实 DOM 频繁排版与重绘的效率是相当低的;</li>
<li>虚拟 DOM 有效降低大面积(真实 DOM 节点)的重绘与排版,因为最终与真实 DOM 比较差异,可以只渲染局部(同2);</li>
</ol>
<p><strong>使用虚拟DOM的损耗计算:</strong></p>
<p>总损耗 = 虚拟DOM增删改 + (与Diff算法效率有关)真实DOM差异增删改 + (较少的节点)排版与重绘</p>
<p><strong>直接使用真实DOM的损耗计算:</strong></p>
<p>总损耗 = 真实DOM完全增删改 + (可能较多的节点)排版与重绘</p>
<h2 id="diff-算法">Diff 算法</h2>
<p>虚拟 DOM 的核心在于 Diff,它自动帮你计算那些应该调整的,然后只修改应该被调整的区域,省下的不是运行速度这种 "小速度",而是开发速度/ 维护速度/ 逻辑简练程度等 "总体速度"。</p>
<p>但虚拟 DOM 快也是在相对条件下的,这里引用 <code>@尤雨溪</code>大大在知乎问题《网上都说操作真实 DOM 慢,但测试结果却比 React 更快,为什么?》上回答的一句话吧:</p>
<blockquote>
<p>不要天真地以为 Virtual DOM 就是快,diff 不是免费的,batching 么 MVVM 也能做,而且最终 patch 的时候还不是要用原生 API。在我看来 Virtual DOM 真正的价值从来都不是性能,而是它 1) 为函数式的 UI 编程方式打开了大门;2) 可以渲染到 DOM 以外的 backend,比如 ReactNative。</p>
</blockquote>
<p><img src="https://img2018.cnblogs.com/blog/1120515/201910/1120515-20191015234043768-924491056.png" alt="" loading="lazy"></p>
<p>Diff 大致可以分为三种类型:</p>
<ul>
<li><strong>Tree Diff:</strong> 新旧两棵 DOM 树,逐层对比的过程,就是 Tree Diff,当整颗DOM逐层对比完毕,则所有需要被按需更新的元素,必然能够找到;</li>
<li><strong>Component Diff:</strong> 在进行 Tree Diff 的时候,每一层中,组件级别的对比,叫做 Component Diff:
<ul>
<li>如果对比前后,组件的类型相同,则<strong>暂时</strong>认为此组件不需要被更新;</li>
<li>如果对比前后,组件类型不同,则需要移除旧组件,创建新组件,并追加到页面上;</li>
</ul>
</li>
<li><strong>Element Diff:</strong> 在进行组件对比的时候,如果两个组件类型相同,则需要进行元素级别的对比,这叫做 Element Diff;</li>
</ul>
<h1 id="三hello-world">三、Hello World</h1>
<hr>
<ul>
<li>引用自:http://www.ruanyifeng.com/blog/2015/03/react.html - 阮一峰 - React 入门实例教程</li>
</ul>
<p>使用 React 的网页源码,结构大致如下(可以直接运行):</p>
<pre><code class="language-html"><!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>
</code></pre>
<p>上面代码有两个地方需要注意。首先,最后一个 <code><script></code> 标签的 <code>type</code> 属性为 <code>text/babel</code> 。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 <code>type="text/babel"</code> 。</p>
<p>其次,上面代码一共用了三个库: <code>react.js</code> 、<code>react-dom.js</code> 和 <code>Browser.js</code> ,它们必须首先加载。其中,<code>react.js</code>是 React 的核心库,<code>react-dom.js</code> 是提供与 DOM 相关的功能,<code>Browser.js</code> 的作用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。</p>
<pre><code class="language-shell">$ babel src --out-dir build
</code></pre>
<p>上面命令可以将 <code>src</code> 子目录的 <code>js</code> 文件进行语法转换,转码后的文件全部放在 <code>build</code> 子目录。</p>
<h2 id="reactdomrender">ReactDOM.render()</h2>
<p>ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。</p>
<pre><code class="language-html">ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</code></pre>
<p>上面代码将一个 <code>h1</code> 标题,插入 <code>example</code> 节点,运行结果如下:</p>
<p><img src="https://img2018.cnblogs.com/blog/1120515/201910/1120515-20191015234044005-755895972.png" alt="" loading="lazy"></p>
<h2 id="jsx-语法">JSX 语法</h2>
<ul>
<li>引用自:https://www.runoob.com/react/react-jsx.html - RUNOOB.COM - React JSX</li>
</ul>
<p>上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写。我们先来看以下一段代码:</p>
<pre><code class="language-html">const element = <h1>Hello, world!</h1>;
</code></pre>
<p>与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。要将 React 元素渲染到根 DOM 节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:</p>
<pre><code class="language-html">var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));
</code></pre>
<p>JSX 看起来类似 HTML ,你也可以在上面代码中嵌套多个 HTML 标签,但是需要使用一个 <code>div</code> 元素包裹它。</p>
<h3 id="javascript-表达式">JavaScript 表达式</h3>
<p>我们可以在 JSX 中使用 JavaScript 表达式。表达式写在花括号 <strong>{}</strong> 中。实例如下:</p>
<pre><code class="language-html">ReactDOM.render(
<div>
<h1>{1+1}</h1>
</div>
,
document.getElementById('example')
);
</code></pre>
<p>在 JSX 中不能使用 <strong>if else</strong> 语句,但可以使用 <strong>conditional (三元运算)</strong> 表达式来替代。以下实例中如果变量 <strong>i</strong> 等于 <strong>1</strong> 浏览器将输出 <strong>true</strong>, 如果修改 i 的值,则会输出 <strong>false</strong>.</p>
<pre><code class="language-html">ReactDOM.render(
<div>
<h1>{i == 1 ? 'True!' : 'False'}</h1>
</div>
,
document.getElementById('example')
);
</code></pre>
<h3 id="样式">样式</h3>
<p>React 推荐使用内联样式。我们可以使用 <strong>camelCase</strong> 语法来设置内联样式. React 会在指定元素数字后自动添加 <strong>px</strong> 。以下实例演示了为 <strong>h1</strong> 元素添加 <strong>myStyle</strong> 内联样式:</p>
<pre><code class="language-html">var myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style = {myStyle}>菜鸟教程</h1>,
document.getElementById('example')
);
</code></pre>
<h3 id="注释">注释</h3>
<p>注释需要写在花括号中,实例如下:</p>
<pre><code class="language-html">ReactDOM.render(
<div>
<h1>菜鸟教程</h1>
{/*注释...*/}
</div>,
document.getElementById('example')
);
</code></pre>
<h3 id="数组">数组</h3>
<p>JSX 允许在模板中插入数组,数组会自动展开所有成员:</p>
<pre><code class="language-html">var arr = [
<h1>菜鸟教程</h1>,
<h2>学的不仅是技术,更是梦想!</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
</code></pre>
<h1 id="参考资料">参考资料</h1>
<hr>
<ol>
<li>http://www.ruanyifeng.com/blog/2015/03/react.html - React 入门实例教程 - 阮一峰</li>
<li>https://www.jianshu.com/p/60100985dd7f - 前端框架与库的区别</li>
<li>https://www.zhihu.com/question/301860721/answer/545031906 - Vue 和 React 的优点分别是什么?</li>
<li>https://zhuanlan.zhihu.com/p/22184194 - 你真的理解 DOM 了吗?</li>
<li>https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model/Introduction - DOM 概述</li>
<li>https://blog.huteming.site/posts/e0c41c5f/ - 为什么说虚拟DOM更快</li>
</ol>
<hr>
<p>按照惯例黏一个尾巴:</p>
<blockquote>
<p>欢迎转载,转载请注明出处!<br>
独立域名博客:wmyskxz.com<br>
简书ID:@我没有三颗心脏<br>
github:wmyskxz<br>
欢迎关注公众微信号:wmyskxz<br>
分享自己的学习 & 学习资料 & 生活<br>
想要交流的朋友也可以加qq群:3382693<br>
钱</p>
</blockquote><br><br>
来源:https://www.cnblogs.com/wmyskxz/p/11681955.html
頁:
[1]