JSX基本原理
如果用JavaScript对象来表现一个DOM元素的结构,例如:
<div class='container' id='main'>
<div class="title">Hello</div>
<button>Click<button>
</div>
每个DOM元素的结构都可以用JavaScript的对象来表示,一个DOM元素包含的信息其实只有三个:标签名,属性,子元素。
因此上面的这段HTML所有的信息都可以用合法的JavaScript对象来表示:
{
tag :'div',
attrs: { className: 'container', id: 'main' },
children: [
{
tag: 'div',
arrts: { className: 'title' },
children: ['Hello']
},
{
tag: 'button',
attrs: null,
children: ['Click']
}
]
}
HTML的信息和上面这段Js传达的信息其实是一样的,只不过从长度和代码结构清晰度上,用HTML会清晰很多。
React.js把JavaScript的语法扩展了一下,编译的过程会把类似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'>使用JSX描述UI信息</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' },
"使用JSX描述UI信息"
)
)
)
}
}
ReactDOM.render(
React.createElement(Header, null),
document.getElementById('root')
);
React.createElement
会构建一个JavaScript对象来描述HTML信息,包括标签名,属性还有子元素等。所以使用React和JSX的时候一定要经过编译的过程。
有了这个HTML结构和信息的对象之后,就可以拿去构造DOM元素了,然后把这个DOM元素塞到页面里。这就是 ReactDOM.render
方法所干的事情:
ReactDOM.render(
React.createElement(Header, null),
document.getElementById('root')
);
总结一下从JSX到页面呈现经历了下面的过程:
那么为什么不直接从JSX直接渲染成可供展示的DOM元素呢?
第一个原因是,当我们拿到一个表示UI的结构时,不一定会把这个元素渲染到浏览器上,也可能是手机App上,所以这也是为什么要把react-dom
专门分离出来的原因。可以想象为,一个叫react-canvas
的模块可以帮我们把UI渲染到浏览器上,一个叫react-native
的模块帮我们把UI渲染到App上(ReactNative)。
第二个原因是,有了这样一个对象,当数据变化,需要更新Component的时候,就可以用比较快的算法(diff算法)操作这个对象,而不用直接操作页面上的DOM,这样可以尽可能少的减少浏览器重拍,极大优化性能。
总结
- JSX 是 JavaScript 语言的一种语法扩展,长得像 HTML,但并不是 HTML。
- React.js 可以用 JSX 来描述你的组件长什么样的。
- JSX 在编译的时候会变成相应的 JavaScript 对象描述。
- react-dom 负责把这个用来描述 UI 信息的 JavaScript 对象变成 DOM 元素,并且渲染到页面上。