JSX的本质(3)
实际上JSX只是React.createElement(component,props,children)函数的语法糖。
1.什么是语法糖?
如果写React.createElement这种太复杂了,我们就延伸出了一种简单的方法,就是说我们写JSX更简单效果却和写React.createElement一样,我们在里面尝到了甜头,可以称为这个函数的语法糖。
JSX最终都会被转换成React.createElement函数的调用。
通过什么转换的?通过babel,如果是写jsx语法,script标签type也要设置成type="text/babel"否则它不会识别JSX语法。
2.查看React.createElement源码
createElement需要传递三个参数:
参数一:type
- 当前ReactElement的类型;
- 如果是标签元素,那么就使用字符串表示 “div”;
- 如果是组件元素,那么就直接使用组件的名称;
参数二:config
- 元素的属性,所有jsx中的属性都在config中以对象的属性和值的形式存储
参数三:children
- 存放在标签中的内容,以children数组的方式进行存储;
3.babel官网查看jsx转换的createElement
babel官网:babeljs.io
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
class App extends React.Component {
constructor() {
super();
}
render() {
return/*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
className: "header"
}, /*#__PURE__*/React.createElement("h2", null, "\u6211\u662F\u5934\u90E8")), /*#__PURE__*/React.createElement("div", {
className: "content"
}, /*#__PURE__*/React.createElement("h2", null, "\u6211\u662F\u9875\u9762\u7684\u5185\u5BB9"), /*#__PURE__*/React.createElement("button", null, "-1"), /*#__PURE__*/React.createElement("button", null, "+1"), /*#__PURE__*/React.createElement("a", {
href: "www.baidu.com"
}, "\u767E\u5EA6")), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("p", null, "\u6211\u662F\u5E95\u90E8")));
}
}
ReactDOM.render(<App />, document.getElementById("app"));
</script>
</body>
</html>
4.虚拟DOM的创建过程
我们会发现最终React.createElement返回(创建)了一个ReactElement对象
而ReactElement最终形成的树结构就是Virtual DOM;
最后使用ReactDOM.render()映射虚拟DOM-》浏览器真实DOM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
class App extends React.Component {
constructor() {
super();
}
render() {
// jsx -> babel -> React.createElement -> ReactElement(对象树) -> React.render() -> 真实DOM
let ReactElementObj = <div>
<div className="header">
<h2>我是头部</h2>
</div>
<div className="content">
<h2>我是页面的内容</h2>
<button>-1</button>
<button>+1</button>
<a href="www.baidu.com">百度</a>
</div>
<div>
<p>我是底部</p>
</div>
</div>;
console.log(ReactElementObj);
return ReactElementObj;
}
}
ReactDOM.render(<App />, document.getElementById("app"));
</script>
</body>
</html>
jsx -> babel -> React.createElement -> ReactElement(对象树) -> React.render() -> 真实DOM
5.为什么使用虚拟DOM?
为什么使用虚拟DOM而不是直接修改真实DOM呢?
- 很难跟踪状态发生的改变:原有的开发模式,我们很难跟踪到状态发生的改变,不方便针对我们应用程序进行调试;
- 操作真实DOM性能较低:传统的开发模式会进行频繁的DOM操作(DOM树会重绘),而这一的做法性能非常的低;
DOM操作性能非常低:
- 首先,document.createElement本身创建出来的就是一个非常复杂的对象。
- 其次,DOM操作会引起浏览器的回流和重绘,所以在开发中应该避免频繁的DOM操作。
举个例子,需要渲染5个li,如果使用原生js来操作dom是一次一次的添加的进行了多次的DOM操作。
对于上面的问题,虚拟DOM就可以帮我们解决这个问题,虚拟DOM帮助我们从命令式编程转到了声明式编程的模式。
React官方的说法:Virtual DOM 是一种编程理念
- 在这个理念中,UI以一种理想化或者说虚拟化的方式保存在内存中,并且它是一个相对简单的JavaScript对象
- 我们可以通过ReactDOM.render让 虚拟DOM 和 真实DOM同步起来,这个过程中叫做协调(Reconciliation)
React设计原则: state中数据的不可变性
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭