DOM 向JSX的演进

网页由 DOM 元素构成。React DOM 并不是浏览器的 DOM,而React DOM 只是用来告诉浏览器如何创建 DOM 的方法。通常情况下,我们并不需要 React 就能创建出一个 DOM 元素,但是 React 创建与管理 DOM 的方式有组件化、虚拟 DOM 等更高层次的抽象,由此带来的优势是更快的渲染速度,以及更好的维护性,因此值得去尝试。

下面分别用 JavaScript 原生方法,React.createElement 方法,以及 JSX 方法来创建一个h1元素,class设置为main,最后挂载在 id 为 root 的 div 元素下面。

html结构应该如下:

<div id="root">
<h1 id="main">Hello React</h1>
</div>

1 document.createElement

JavaScript原生方法,没有过多需要解释的部分。

// 方法1:document.createElement
const title = document.createElement('h1');
title.innerText='Hello React (method 1)';
title.className='main';
document.getElementById('root').appendChild(title);

2 React.creaetElement

第二种方法是用 React 的 createElement 来创建 React DOM。

// 方法2:React.createElement
import React from 'react';
import ReactDOM from 'react-dom'; const title = React.createElement("h1", {className: "main"}, "Hello React (method 2)");
ReactDOM.render(title, document.getElementById('root'));

其中 createElement(a, b, c)

  • 第一个参数 a:表示元素的类型,比如:h1, div 等。
  • 第二个参数 b:表示该元素上的属性,使用 JavaScript 对象方式表示。
  • 第三个参数 c:表示该元素内部的内容(子元素),可以是文字,可以继续嵌套另外一个 React.createElement(a, b, c)

这种方法其实在实际 React 开发中几乎不会使用,因为可以直接 JSX 方法。

3 JSX

JSX 是一种 JavaScript 的语法糖。Facebook 开发JSX出来,主要用于 React 中。虽然 JSX 的内容会长得像 html,但还是 JavaScript。

用 JSX 方法来创建 React DOM 的代码如下:

// 方法3:JSX
import React from 'react';
import ReactDOM from 'react-dom'; const title = (
<h1>Hello React (method 3)</h1>
); ReactDOM.render(title, document.getElementById('root'));

3.1 代码逐行解读:

第1行: import React from 'react';

有 JSX 的地方,在文件开头就需要引入 React,因为实际上 JSX 是使用了 React.createElement,JSX 只是一个JS 的语法糖,所以需要引入 React 包,否则会报错。

第2行: import ReactDOM from 'react-dom';

react-dom 是一个把React 代码渲染到网页端的包。如果在移动端渲染,就需要使用 React Native 的相关包。 目前(截至2017年12月3日),React 与 ReactDOM 都更新到了 16.0.0,所以在 package.json 中可以看到这两个版本都是最新的版本。

第4-6行:

const title = (
<h1>Hello React (method 3)</h1>
);

这就是一段 jsx 代码,实际是 React.createElement 创建一个 React DOM 对象,完全等同于下面这行代码。

const title = React.createElement("h1", {className: "main"}, "Hello React (method 3)");

JSX 更加直观,符合我们对 html 结构的认知,如果都用 React.createElement 去创建 React DOM,会非常的繁琐,且容易出错。

第8行:

ReactDOM.render(title, document.getElementById('root'));

把上面创造出来的 React DOM 对象(即虚拟DOM),渲染到网页 id 为 root 的元素中。

3.2 JSX的限制:标签的包裹

但是 JSX 有一个限制,就是在 JSX 中 html 代码第一层只能写一个元素。如果有多个标签(元素)并列,形成所谓的相邻JSX元素(adjacement jsx elements),就会报语法错误。通常这种多元素并列的情况,就用在它们外面包裹一层 div。

(1) 错误的代码

举例来看,如果 index.js 写成如下代码:

// 没有 div 包裹会报错
import React from 'react';
import ReactDOM from 'react-dom'; const title = (
<h1>Parallel elements demo</h1>
<p>Content</p>
); ReactDOM.render(title, document.getElementById('root'));

命令行中会报语法错误:相邻 JSX 元素必须用封闭的标签包裹。

Module build failed: SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag (35:2)
(2) 正确的代码

相邻元素 Adjacent JSX elements,在这里其实就是并列的 h1 与 p 标签。所以这里的解决方法就是用一个 div 标签来包裹 h1 与 p 标签。

// 正确写法:用 div 包裹并列标签
import React from 'react';
import ReactDOM from 'react-dom'; const title = (
<div>
<h1>Parallel elements demo</h1>
<p>Content</p>
</div>
); ReactDOM.render(title, document.getElementById('root'));

3.3 突破JSX标签包裹限制

注意:如果刚接触 React,这部分内容可以跳过后面再来看。

对于 jsx 外层需要包裹一层 div,如果要突破这个限制,目前有两种方法:

  • 返回数组
  • 使用高阶组件做辅助
(1) 返回数组

如果的是数组,就没有问题。

// 突破JSX标签包裹限制1:返回数组
import React from 'react';
import ReactDOM from 'react-dom'; const arr = ['Adams', 'Bill', 'Charlie']; const Arr = () => {
return arr.map((item, index) => {
return <p key={index}>{item}</p>
})
} ReactDOM.render(<Arr />, document.getElementById('root'));

这里是一个数组 arr,包含三个名字,然后用 map 方法得到一个包含三段 JSX 代码的数组。注意这里需要写成匿名函数,然后以 <Arr /> 自封闭标签的格式放入 ReactDOM 的第一个参数位置去渲染。

当然,这段代码还可以进行简写:

第一种简写 map 中的剪头函数少了 return

// 简写1
import React from 'react';
import ReactDOM from 'react-dom'; const arr = ['Adams', 'Bill', 'Charlie']; const Arr = () => {
return arr.map((item, index) => <p key={index}>{item}</p>);
}; ReactDOM.render(<Arr />, document.getElementById('root'));

第二种简写是 Arr 这个匿名函数少了 return。

// 简写2
import React from 'react';
import ReactDOM from 'react-dom'; const arr = ['Adams', 'Bill', 'Charlie']; const Arr = () => (arr.map((item, index) => <p key={index}>{item}</p>)); ReactDOM.render(<Arr />, document.getElementById('root'));
(2) 高阶组件(High Order Component, hoc)

div 去包裹并列元素的痛点是,我们可能并不需要这个多余的 div 标签,可能会破坏 html 结构,也许上层做了 flex,并不能有效的传递到这些并列标签上。

所以这里引入了用于辅助的高阶组件 hoc。虽然高阶组件的名字听起来很吓人,然而做的事情很简单,就是传递的作用。

// 突破JSX标签包裹限制:方法2 高阶组件
import React from 'react';
import ReactDOM from 'react-dom'; const Aux = props => props.children; const title = (
<Aux>
<h1>Parallel elements demo</h1>
<p>Content</p>
</Aux>
); ReactDOM.render(title, document.getElementById('root'));

在上面这段代码中,const Aux = props => props.children; 就是高阶组件。Aux 这个高阶组件的作用是把标签包括的内容进行传递和显示(Aux 是英文中的 auxiliary辅助的)。查看最终 html 结构会发现 div 已经消失了,而且代码没有 div 也能正常。

高阶组件不仅仅是这里的传递作用,在 Redux 中会大量使用,后面会讲到。

另外,据称 React 16.2 开始有一个所谓的 fragment 的做法,就是 React 自带了 <Aux></Aux>,但是写成 <></>。在 React 16.2,代码可以写成如下格式:

import React from 'react';
import ReactDOM from 'react-dom'; const title = (
<>
<h1>Parallel elements demo</h1>
<p>Content</p>
</>
); ReactDOM.render(title, document.getElementById('root'));

React.createElement 与 JSX的更多相关文章

  1. 学习React从接受JSX开始

    详情参考官方JSX规范 虽然JSX是扩展到ECMAScript的类XML语法,但是它本身并没有定义任何语义.也就是说它本身不在ECMAScript标准范围之内.它也不会被引擎或者浏览器直接执行.通常会 ...

  2. 从 0 到 1 实现 React 系列 —— 1.JSX 和 Virtual DOM

    看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...

  3. React 学习(一) ---- React Element /组件/JSX

    学习React的时候,你可能听到最多的就是要先学习webpack, babel,要先学会配置然后才能学react 等等,一堆的配置就把我们吓着了,根本就没有心情就学习react了.其实在最开始学习re ...

  4. React学习笔记 - JSX简介

    React Learn Note 2 React学习笔记(二) 标签(空格分隔): React JavaScript 一.JSX简介 像const element = <h1>Hello ...

  5. react中的jsx详细理解

    这是官网上的一个简单的例子 const name = 'Josh Perez'; const element = <h1>Hello, {name}</h1>; ReactDO ...

  6. 假如React没了JSX

    如题,想必React大家早已不陌生,而React里面的JSX都是玩的得心应手了,但是假如说React里面没有了React那会是一种什么样的情形呢,我们来简单的看一下. 首先我们来实现一个简单的list ...

  7. react 闲谈 之 JSX

    jsx元素-> React.createElement -> 虚拟dom对象 -> render方法 1.在react中想将js当作变了引入到jsx中需要使用{} 2.在jsx中,相 ...

  8. React的React.createElement源码解析(一)

    一.什么是jsx  jsx是语法糖  它是js和html的组合使用  二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法  jsx语法通过babel转化为 ...

  9. React.createClass 、React.createElement、Component

    react里面有几个需要区别开的函数 React.createClass .React.createElement.Component 首选看一下在浏览器的下面写法: <div id=" ...

随机推荐

  1. 亲密字符串之Javascript解法

    本题为leetcode第859题,原题链接在此:https://leetcode-cn.com/problems/buddy-strings/submissions/ 给定两个由小写字母构成的字符串  ...

  2. React学习:状态(State) 和 属性(Props)

    State 与 Props 区别props 是组件对外的接口,state 是组件对内的接口.组件内可以引用其他组件,组件之间的引用形成了一个树状结构(组件树),如果下层组件需要使用上层组件的数据或方法 ...

  3. orangepi自启动打开一个终端并且运行脚本

    第一步: 在 /home/pi/.config 下创建一个文件夹,名称为 autostart,如果已经存在则不需要创建 第二步: 在autostart文件夹中创建桌面启动项文件,(文件名以 .desk ...

  4. ConcurrentHashMap源码解析(JDK8)

    首先看看CHM的重要成员变量: public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ...

  5. Charles中文破解版下载安装及使用教程(附带免费下载链接)

    一. 简介及安装 Charles 是在 PC 端常用的网络封包截取工具,但它不仅仅能在pc端使用,还可以在手机ios和安卓端都可以使用.我们在做移动开发或者测试网页app时候,为了调试与服务器端的网络 ...

  6. redis 异常 MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk

    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. 解决方 ...

  7. RabbitMQ direct交换器

    1:队列和交换器多次绑定 String[] routekeys={"routekey1","routekey2","routekey3"}; ...

  8. (备忘)解决用Xftp向CentOS7 传文件速度慢的问题

    问题原因:之前用XFTP上传文件的时候一直挺好的,今天突然速度特别慢,上传了一个多小时也没把一个一百兆的文件成功上传 查询过程: 1.网络原因:网络的确有点卡,但不至于这么慢吧,几K的速度,鉴于网络问 ...

  9. Keras实现Self-Attention

    本文转载自:https://blog.csdn.net/xiaosongshine/article/details/90600028 一.Self-Attention概念详解 对于self-atten ...

  10. 2013.4.29 - KDD第十一天

    今天上午在图书馆写FIrst集,真心没写出来,算法是昨天找好的,不过实现的话还是需要很大的代码量,然后就打算用郑茂或者韩冰的代码了. 晚上图书馆快关门的时候开始思考KDD的问题, 我一开始打算给中秋发 ...