React是用于构建用户界面的 JavaScript 库,相当于MVC里面的V(view),但又不完全是view。组件化是它的一个显著特点,而jsx是一种对javascript的扩展。jsx用的频率很高,但搞懂它的运作原理估计很少人去探索,那么今天就来一起探索一下,为什么要有这种语法,它是经过怎么样的转化变成页面的元素的。
什么是jsx?
本质上来讲,JSX 只是为 React.createElement(component, props, …children) 方法提供的语法糖。
思考一个问题:如何用 JavaScript 对象来表现一个 DOM 元素的结构,举个例子:
<div class="demo" >
<p class="childDemo"> Click Me</p>
</div >
每个 DOM 元素的结构都可以用 JavaScript 的对象来表示。你会发现一个 DOM 元素包含的信息其实只有三个:标签名,属性,子元素。
其实上面这个 HTML 所有的信息我们都可以用合法的 JavaScript 对象来表示:
{
tag: 'div',
attrs: { className: 'demo'},
children: [
{
tag: 'p',
arrts: { className: 'childDemo' },
children: ['Click Me']
}
]
}
你会发现,HTML 的信息和 JavaScript 所包含的结构和信息其实是一样的,我们可以用 JavaScript 对象来描述所有能用 HTML 表示的 UI 信息。但是用 JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。
于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
class Header extends Component {
render () {
return (
<div>
<h1 className='title'>React 小书</h1>
</div>
)
}
}
ReactDOM.render(
<Header />,
document.getElementById('root')
)
经过编译后:
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
class Header extends Component {
render () {
return (
React.createElement(
"div",
null,
React.createElement(
"h1",
{ className: 'title' },
"React 小书"
)
)
)
}
}
ReactDOM.render(
React.createElement(Header, null),
document.getElementById('root')
);
React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等。这样的代码就是合法的 JavaScript 代码了。所以使用 React 和 JSX 的时候一定要经过编译的过程。
这里再重复一遍:所谓的 JSX 其实就是 JavaScript 对象。每当在 JavaScript 代码中看到这种 JSX 结构的时候,脑子里面就可以自动做转化,这样对你理解 React.js 的组件写法很有好处。
有了这个表示 HTML 结构和信息的对象以后,就可以拿去构造真正的 DOM 元素,然后把这个 DOM 元素塞到页面上。这也是我们最后一段代码中 ReactDOM.render 所干的事情:
ReactDOM.render(
<Header />,
document.getElementById('root')
)
ReactDOM.render 功能就是把组件渲染并且构造 DOM 树,然后插入到页面上某个特定的元素上(在这里是 id 为 root 的 div 元素)
总结一下jsx渲染到页面的过程:
有些同学可能会问,为什么不直接从 JSX 直接渲染构造 DOM 结构,而是要经过中间这么一层呢?
第一个原因是,当我们拿到一个表示 UI 的结构和信息的对象以后,不一定会把元素渲染到浏览器的普通页面上,我们有可能把这个结构渲染到 canvas 上,或者是手机 App 上。所以这也是为什么会要把 react-dom 单独抽离出来的原因,可以想象有一个叫 react-canvas 可以帮我们把 UI 渲染到 canvas 上,或者是有一个叫 react-app 可以帮我们把它转换成原生的 App(实际上这玩意叫 ReactNative)。
第二个原因是,有了这样一个对象。当数据变化,需要更新组件的时候,就可以用比较快的算法操作这个 JavaScript 对象,而不用直接操作页面上的 DOM,这样可以尽量少的减少浏览器重排,极大地优化性能。
总结
要记住几个点:
- JSX 是 JavaScript 语言的一种语法扩展,长得像 HTML,但并不是 HTML。 React.js 可以用
- JSX来描述你的组件长什么样的。 JSX 在编译的时候会变成相应的 JavaScript 对象描述。
- react-dom负责把这个用来描述UI 信息的 JavaScript 对象变成 DOM 元素,并且渲染到页面上。