React进阶(七)模板语言JSX与虚拟DOM

梦 想

我们想要创建一个组件,首先需要理解一个重要的概念:JSX

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

这种类似于html代码的东西就是JSX。我们可以简单的将其理解为一种渲染数据的模板语言。有接触过其他模板语言的同学应该知道,模板语言其实是为了简化直接调用DOM API来渲染数据的复杂度,模板语言的本质仍然是JS代码。记住这个特性,在理解虚拟DOM这个重要概念时会大有帮助。

在React的组件中,只有引入了React的模块才能正确识别JSX代码。

// 必不可少
import React from 'react';

JSX与html非常类似,因此如果你对html已经非常熟悉的话,使用JSX就非常简单。但除此之外,JSX还具有模板语言的特性。

  • 可以在JSX中使用表达式
const ele = <h1>Hello, {name}!</h1>

const ele = <h1>{sayHello('alex')}!</h1>

const ele = <h1>{condition ? 'React' : 'React Native'}!</h1>
  • 每一个标签都可以接收属性
const element = <div tabIndex="0">注意观察属性</div>
const element = <div tabIndex={0}>注意观察属性</div>
const element = <div tabIndex={num}>接收变量</div>

JSX默认支持所有html标签,并且支持所有html标签默认的属性。不过需要注意的是,为了与创建类的关键字class区分开,html标签的class属性在JSX中使用className代替。

const element = <div className="index">Hello world.</div>
  • 作为返回结果

在引入了React的模块中,我们可以自定一个返回JSX模板的函数,也可以让JSX参与到条件判断中。

import React from 'react';

...

function getResult(type) {
  if(type === 'React') {
    return <div>React</div>
  } else {
    return <div>React Native</div>
  }
}

当我们需要自定义组件时,这种场景会用得非常多,往往我们都需要根据传入的不同状态值动态的判断哪些是我们需要的。

  • 使用[].map暂时列表数据

当我们想要渲染一列数据时,可以借助数组中的map方法。

const data = [1, 2, 3, 4, 5, 6, 7];

<div className="wrapper">
  {data.map((item, i) => (
    <div className="num" key={i}>{item}</div>
  ))}
</div>

实践中,我们有的时候总会逼不得已需要在JSX中处理许多逻辑代码,这个时候就必须要将逻辑代码放入{}中来处理。

const condition = true;

<div className="wrapper">
  {condition && <div>hello</div>}
</div>

但是如果使用不善,会导致JSX的可读性变得非常低,因此如果大家在使用过程中发现JSX变得越来越乱越来越复杂,则建议有意识的去寻找优化方法,不断的提高自己React的使用水平。

  • JSX的本质是js对象

对于一个我们非常属性的html标签div,我们可以用一个JSON对象去描述它。

const div = {
  // 名字
  name: 'div',
  // 属性
  props: { className: 'wrapper', tabIndex: 0,  ... }

  // 父节点
  parentNode: h1<Object>,

 // 子节点
  children: [div<Object>, span<Object>],

   ...
}

这里的属性我就随意命名,大概表达意思。我们也可以通过浏览器的开发者工具将一个标签打印出来观察,也会发现每一个标签其实也是一个对象。那样我们会有更加直观的感受。

html中的div元素

因此,模板语言JSX本质上是一个JS对象的语法糖,这样能够更加方便我们使用,React同样也提供了如图类似的方式来创建一个JSX标签。

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

// Note: this structure is simplified
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

也正因为如此,我们可以将JSX的标签对象一一映射到html的标签对象中。React就是借助这样的方式,帮助我们将JSX渲染到html的文档中。

虚拟DOM

正是因为JSX模板与html模板具有极为相似的特性,React可以借助这样的特性将JSX渲染到html中。但同时JSX与html又是不同的东西,因此我们可以简单粗暴的理解JSX就是虚拟DOM(render方法的执行结果)

  • 为什么要使用虚拟DOM

DOM操作是一件成本很高的事情。
如果你曾经有过页面性能优化的经验,一定会非常认可上面这句话。对于浏览器而言,每一次DOM操作都伴随着大量的计算,也正因为这样,当页面需要的操作不断变得复杂,每一次操作需要改动的元素变得更多时,浏览器的压力也会越来越大。

大家可以在开发者工具中找到Rendering,勾选Paint flashing,这样就可以观察一个页面中元素的变动。浏览器会自动将被重绘的元素高亮显示出来。

image.png

如果你还没有了解过重绘回流的概念,那么说明你需要去补充一下基础知识了,这里不做深入讲解。

那么虚拟DOM是如何帮助浏览器解决这个问题的呢?

正常情况下,我们操作是直接改动html元素。每一次操作都会给浏览器增加更多的压力。
而虚拟DOM可以帮我们收集短时间来的多次改动,汇总成为一次改动。这样对于浏览器来说,压力就减少了很多。如图。

image.png

这就是虚拟DOM的批处理能力。当然,计算的压力同样存在,但是因为虚拟DOM是JS计算的,因此这样的方式将本来属于浏览器的压力让JS来抗,而我们知道,JS的抗压能力是比浏览器优秀很多的。

除了批处理能力,React中虚拟DOM的diff算法也是一大亮点,不过因为是初学阶段,这里不做深入讲解,也不建议大家太早的关注更深层次的知识。如果有兴趣的同学可以参考 https://zhuanlan.zhihu.com/p/20346379

讲个题外话。

最近发现了一个非常有意思的事情。

一个小哥在某个群里问React到底比jQuery好在哪?可能很多人都会觉得这真的是一个很傻的问题,然而这个Java开发的小哥哥确实从心底认为jquery很好用,反而React学习成本很高,也用的不太舒服,所以它的好处到底在哪里,为什么大家都不用easyUI了?

本来这是一件很小的事情,但是突然想到之前也遇到一个类似的事情,一个组里的小伙伴很疑惑为什么我们要用async/await?我试图解释了半天他也理解不了这个东西到底好在哪里。

同样的事情还发生在我自己身上,为什么我们还要去费劲心思去学typescript?JS不是很好用嘛,干嘛要去学一个超集?当初ts刚出来的时候名声大噪,也动手去尝试了它的语法,真的感觉很麻烦,用起来加那么多限制条件,鼓捣了一下午也没觉得typescript到底好在哪里。于是放弃。正是因为认知的原因,傻乎乎的错过了好久typescript,直到3.0出来了,才在机缘巧合之下惊喜的发现哇靠,typescript简直就是神器,这才深深的感受到自己真的错过了太多。

最近我特别留意了蛮多正在学习React的同学,或者已经学了很长时间甚至已经在工作中使用React的同学,发现很多人并没有发现React到底好在哪里。而大家关注的重点往往是,某个功能用React应该怎么实现,而不是React这样实现,好在哪里 ~,往往大家学习React的起因也不是因为已经感受到了React带来的好处才去学的。这样不同的认知与不同的学习源动力,自然会导致截然不同的学习效果。就连学习效率也会天差地别。

正如我之前说过的,工作经验丰富<非工作年限>的开发人员更能够直接的体会到新东西(React/Typescript)等的优势,因为经历过前端开发刀耕火种的年代,自然就明白模块化组件化虚拟DOM等概念的重要意义,也就更容易把这些知识看得更加重要,视若珍宝。而初学者直接上来就接触这些概念,就常常只会把他们当成一个普通的知识点去学,然后遗忘,所以同样的东西在不同的人眼中就不一样。

so, 经验丰富的前端开发者也不会有想要去嘲讽jQuery怎么这么难用,因为我们确确实实经过了一些事情,那个年代jQuery就是神器,尽管现阶段jquery已经慢慢被弃用,但是它在整个前端发展历程中的意义仍然无法替代。所以如果我们在技术群里偶尔看到某个程序员用着React/vue嘲讽jQuery的时候,就凭这一点就可以知道这个人一定资历尚浅,强行装逼。

对于新手来说,要怎么去感受到React的好,我也没有什么切实可行的办法,只是告诉大家有这样的一个现象,因为我自己也深陷其中,也许到了某个阶段,自然就明悟了也说不定,我只能在文章里告诉大家这个东西很重要,但是总归没有自己切身体会来得深刻,毕竟搞得全文都是重点最终给人的感觉也只是全文都不是重点,所以学习这种东西,看努力,不过要走在行业前列,更看天赋,看领悟,看运气。大抵如此。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容