初衷
使用 React 有一段时间了, 一直想找个时间写一个 React 的系列文章。忙里抽闲,完成了第一篇。写这系列文章的初衷是总结这段时间的技术学习,以及给那些想学习 React 的同学们一点帮助。我会尽量以通俗易懂的语言阐述我对 React 的理解,希望能照顾到更多的新手。相信大家应该都明白一个道理,最能够带领你进步的,并不是比你强很多很多的大牛,而是刚好比你走得快那么一步的脚印。
为什么是React
Hello World
我们从最简单的 Hello World 开始,进入 React 的世界,使用的是最新的 React 16版本。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root"></div>
// 引入react及react-dom库
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
// 引入babel
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
// 在babel编译的环境下执行
<script type="text/babel">
const vDom = <h1>Hello World</h1>
const root = document.getElementById('root')
ReactDOM.render(vDom, root)
</script>
</body>
</html>
复制代码
在使用 React 之前,我们需要先引入 React 相关的 js 库。
- react.development.js 这是 React 的核心库,用于构建页面 UI
- react-dom.development.js 这是 React 的 DOM 相关操作库,可以将你构建的 UI 渲染到浏览器中
除此之外,还需引入 babel 进行语法解析转换。
我们来详细解析下上面的 demo,其实 script 标签中一共就写了3句代码,但其中包含了 React 的核心知识点——虚拟 DOM 和 JSX 。
<script type="text/babel">
const vDom = <h1>Hello World</h1>
const root = document.getElementById('root')
ReactDOM.render(vDom, root)
</script>
复制代码
JSX
JSX 是 React 的灵魂,全称 JavaScript XML。顾名思义,它可以让你在 JS 中使用 XML 标记的方式去直接声明界面的 DOM,这是 React 独有的语法糖。
请看 HelloWorld 的例子
const vDom = <h1>Hello World</h1> // 创建h1标签,右边千万不能加引号
const root = document.getElementById('root') // 找到<div id="root"></div>节点
ReactDOM.render(vDom, root) // 把创建的h1标签渲染到root节点上
复制代码
这里我们在 JS 里直接创建了一个<h1>Hello World</h1>
标签,并赋值给 vDom,这就是 JSX 语法。
如果我们将 react 库的引入注释掉
ReactDOM.render()
这个是 react-dom 库中的方法,用于将你创建好的 HTML 模板(虚拟 DOM 节点)插入到某个节点上,并渲染到页面上。第一个参数是 HTML 模板,第二个参数是指定的 DOM 节点。
在上述 JSX 语法中有几个值得注意的地方:
- 右边的 h1 标签千万不能加引号。如果加上引号的,JS 引擎会将其解释为字符串类型。其实从本质来说,
<h1>Hello World</h1>
这是一个对象,叫做虚拟 DOM 对象,后面会讲到。 <script>
标签的 type 属性为text/babel
。由于使用了 JSX 这种特殊的语法,我们不能再像往常一样,使用<script type="text/javascript">
来解析 JSX,而要借助 babel 来进行解析、转换成 JS。- 将 JSX 语法转为 JavaScript 语法,这一步很消耗时间。所以现在前端项目,都会使用工作流的形式来构建,不会在 html 页面中直接引入 react、写 js 代码等等。
简单来说,就是 JSX 赋予我们在 JS 中直接创建 HTML 标签的能力,因为 HTML 标签实在是太弱小了。
当然我们也可以不使用 JSX 的语法创建 DOM 节点,直接使用 React 给我们提供的普通 JS 写法,React.createElement()
API 来创建。
const vDom = React.createElement(
'h1', // 第一个参数是标签名,例如h1、span、table...
{ className: 'hClass', id: 'hId' }, // 第二个参数是个对象,里面存着标签的一些属性,例如id、class等,因为class是保留字,所以要写成className的形式
'hello world' // 第三个参数是节点中的文本
)
const root = document.getElementById('root')
ReactDOM.render(vDom, root)
复制代码
可以看到和之前的 JSX 写法const vDom = <h1>Hello World</h1>
效果是一样的
React.createElement()
这种写法时,我们并不需要用 babel 进行解析,因为这本身就是 JS 的语法,JS 引擎可以解析。
React.createElement()
API 的一颗语法糖而已,他执行最终会被 babel 解析转换为
React.createElement()
的形式,所以推荐使用 JSX 的语法来创建页面的 UI(也就是 HTML 的一些 DOM)。
JSX的优点
- 类 XML 语法结构清晰
- 增强 JS 语义
- 屏蔽 DOM 操作
- ···
我们以前在操作时,需要经过以下流程
创建节点 -> 找到插入位置 -> 插入节点,若是还有子节点,还需要继续添加,一切都需要手动实现。
而使用 React 的 JSX 语法只需要const vDom = xxx
然后ReactDOM.render(vDom, root)
就可以。
换句话说,以前都是过程式操作,你不仅知道要做什么,还需要自己手动去实现。而现在变成了声明式操作,就好比在下命令一样,你只需要下命令创建怎样的 DOM 节点,然后下命令插入,中间的过程全部都由 React 框架帮你自动实现,让开发者可以完全屏蔽 DOM 的操作。
JSX基本语法规则
- 遇到 HTML 标签(以 < 开头),就用 HTML 规则解析
- 遇到代码块
{}
或括号()
,就用 JavaScript 规则解析
我们把 Hello World 的例子提升下
<script type="text/babel">
let title = 'Hello World'
const vDom = (
<div>
<h1>{title}</h1>
</div>
)
const root = document.getElementById('root')
ReactDOM.render(vDom, root)
</script>
复制代码
上述代码在执行时,当遇到<div>
的左箭头括号时,使用 HTML 的解析规则,当遇到{title}
时,采用 JS 的规则解析,也就是获取变量 title 的值。值得一提的是,如果需要创建嵌套的 HTML 结构,推荐使用()
括号括起来。
虚拟DOM
- 我们在写前端页面时,手动操作 DOM,繁琐又容易出错,在大规模应用下维护起来也很困难。
- 并且每次修改 DOM,浏览器的 DOM 树都需要重绘重排,效率十分低下。
- 既然 DOM 手动操作太繁琐且效率低下,那就在每次状态更新时重新渲染整个页面
- 每次都重新渲染整个页面效率十分低下,所以就加上一个虚拟 DOM
- 每次修改时,先在虚拟 DOM 上更新,最后在批量更新整个页面,这样页面只需要一次大的更新,效率很高
虚拟 DOM 是在 DOM 的基础上建立的一个抽象层,我们对 DOM 中的数据和状态所做的任何改动,都会被自动且高效的同步到虚拟 DOM,最后再批量同步到 DOM 中。React 会在内存中维护一个虚拟 DOM 树,当我们对这个树进行读或写的时候,实际上是对虚拟 DOM 进行的。当数据变化时,React 会自动更新虚拟 DOM 树,然后拿新的虚拟 DOM 树和旧的虚拟 DOM 树进行对比(当中有 DOM diff算法,这个之后再说),把不同的虚拟节点放到一个队列里,最终在渲染时一次批量更新这些队列中的虚拟节点到真实 DOM 中,这是对 DOM 渲染效率上的一个质的提升。
一点小结
React 以 JS 为中心,以 JSX 的独特语法糖将"HTML"放到了 JS 里,而 JS 远比 HTML 要强大。因此,与其增强 HTML 让其拥有逻辑,不如增强 JS 让其支持标签化,这样一来既丰富了 JS 操控领域,又提升了页面渲染的性能。所以,你若是新手也没关系,只要你 JS 能力足够强,相信一定能在 React 的世界里策马奔腾!
最后推荐几个 React 的社区
React 官方文档:react.docschina.org/
React China:react-china.org/
React 开源中国社区:www.oschina.net/translate/t…
我的 github 地址:github.com/FightingHao
如果有什么不懂的地方,欢迎评论,大家一起探讨 React 有关的知识!