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. 只要200行JavaScript代码,就能把特斯拉汽车带到您身边

    Jerry的前一篇文章 如何使用JavaScript开发AR(增强现实)移动应用 (一) 介绍了用React-Native + ViroReact开发增强现实应用的一些预备知识. 本文咱们开始进入增强 ...

  2. WSDL知识点

    WSDL 是基于 XML 的用于描述 Web Services 以及如何访问 Web Services 的语言. WSDL简介 1.什么是 WSDL? WSDL 指网络服务描述语言 WSDL 使用 X ...

  3. lvm快照备份mysql

    快照备份原理(从其他博客看的): 原理:通过lvm快照给lvm真身拍个照片,当lvm真身发送改变时,lvm快照把lvm真身改变之前的内容存放在快照上,这样在lvm快照有效的这段时间内,我们看到的lvm ...

  4. JDK源码那些事儿之LinkedTransferQueue

    在JDK8的阻塞队列实现中还有两个未进行说明,今天继续对其中的一个阻塞队列LinkedTransferQueue进行源码分析,如果之前的队列分析已经让你对阻塞队列有了一定的了解,相信本文要讲解的Lin ...

  5. 原生js获取display属性注意事项

    原生js获取diaplay属性需要在标签上写行间样式style='display:none/block;' <div style="display:block;">&l ...

  6. Django --- ajax结合sweetalert使用,分页器,bulk_create批量创建数据

    目录 ajax结合sweetalert使用 bulk_create批量插入数据 分页器的使用 ajax结合sweetalert使用 ajax可以在不刷新页面的情况下与后端进行交互,在对数据进行操作的时 ...

  7. SIGAI机器学习第二十一集 AdaBoost算法2

    讲授Boosting算法的原理,AdaBoost算法的基本概念,训练算法,与随机森林的比较,训练误差分析,广义加法模型,指数损失函数,训练算法的推导,弱分类器的选择,样本权重削减,实际应用. 大纲: ...

  8. MySQL 数据库,主键为何不宜太长长长长长长长长?

    回答星球水友提问:沈老师,我听网上说,MySQL数据表,在数据量比较大的情况下,主键不宜过长,是不是这样呢?这又是为什么呢? 这个问题嘛,不能一概而论: (1)如果是InnoDB存储引擎,主键不宜过长 ...

  9. PostgreSQL物理坏块和文件损坏案例分享

    作者简介 王睿操,平安好医数据库架构岗,多年postgresql数据库运维开发工作.曾就职于中国民航信息,迪卡侬.对其他数据库产品也有一定的涉猎. 背景 笔者最近发现很多朋友经常遇到PostgreSQ ...

  10. WinDbg 图形界面功能(一)

    当我们启动windbg后,我们就能看到Windbg的样子了,如下: 本部分讨论 WinDbg 图形用户界面的元素. 这些元素包括以下各项:菜单.工具栏和快捷键.菜单有:文件菜单.编辑菜单.视图菜单.调 ...