使用React后为什么不再需要jQuery呢?
首先
我写这篇文章是为了那些完全不了解React(通常称为React.js)或者看了一些文章却不明白它是什么的人。
目的是让只会「只知道jQuery」的人具体了解氛围,这不是面向已经有动力的人的教程。只要有动力,读一下日文版文档并动手操作就能迅速掌握,所以我们的目标是让人们产生足够的兴趣来做到这一点。
以后我们将使用ES2015(ES6)语法(例如箭头函数等)。如果对此部分感到困惑的人,请先了解箭头函数和const语法,然后再继续前进。
在以下说明中,此图标表示的是(从2023年的角度来看)”旧故事”。当你编写新代码时,通常不需要了解这些内容,但为了在查看旧文章时避免混淆,这些内容作为参考信息写在这里。本文本身会定期更新,以跟进React的最新动态并进行修订。
是React所要做的
React 做的事情非常简单,API 也很少。它在”少记忆力却能力强”方面无人能敌。它的少数API已经足以驱逐掉大部分人们熟悉并喜欢使用的jQuery方法,可见其威力之大。
React 是一个用于构建用户界面的 JavaScript 库。它通过将应用程序分成多个可重用的组件来简化界面开发。React 通过使用虚拟 DOM 来实现高效的更新,并提供了强大的状态管理功能。
- 利用一个保存了页面状态的“纯 JavaScript 对象”,通过作用一个“模板式的函数”,来提取出称为“虚拟 DOM”的 DOM 设计图,并利用该设计图来构建真实的 DOM。
请将“这里所说的’纯粹的 JavaScript 对象’是指仅解析 JSON 即可获取的对象,不包含任何标签字符串,仅包含干净的数据”的意思,用中文进行同义表达。
从Web API等获得原始对象,然后使用jQuery创建DOM是一个常见的操作。例如,在”显示商品数据列表”的场景中,可以像这样直接进行操作。
$.getJSON("/api/items").then((data) => {
const ul = $("ul.item-list").empty();
data.items.forEach((item) => {
const li = $("<li>").addClass("item").appendTo(ul);
if (item.stock === 0) li.addClass("soldout");
$("<div>").addClass("item-name").text(item.name).appendTo(li);
$("<div>").addClass("item-price").text(item.price).appendTo(li);
});
});
我并没有做什么困难的事情,但它的外观不够直观。
用 React 撰写相同的内容会产生完全不同的外观(行数增加是因为对函数进行了拆分)。
// ItemListのコンポーネント定義(実体は関数)
const ItemList = (props) => {
return (
<ul className="item-list">
{props.items.map((item) => (
<ItemDetail item={item} />
))}
</ul>
);
};
// ItemDetailのコンポーネント定義(実体は関数)
const ItemDetail = (props) => {
const item = props.item;
return (
<li className={"item" + item.stock === 0 ? " soldout" : ""}>
<div className="item-name">{item.name}</div>
<div className="item-price">{item.price}</div>
</li>
);
};
fetch("/api/items")
.then((res) => res.json())
.then((data) => {
ReactDOM.createRoot().render(
<ItemList items={data.items} />, // これを
document.getElementById("container") // ここにレンダーしろ
);
});
嗯,总之就是有人看到长相奇怪的像是HTML标签的东西就立即想逃回家的情况对吧。然而在React中,JavaScript和HTML(?)的结合就是基本规范。嗯,请稍微忍耐一下吧。作者刚开始也讨厌这个外观,打算逃开,但不到一天就改变了主意。稍后我会详细解释一些,但总之这个“标签”实际上只是一个简单的函数调用而已,通过Babel等工具转换成函数调用形式,所以这只是JavaScript而已。代替$.getJSON()的是通过fetch来实现,当然你也可以使用superagent或axios,无妨。
不再直接切割或粘贴DOM部分了,取而代之的是定义了两个函数(组件)。每个函数返回了一些类似于“HTML标签”的东西,其中嵌入了JavaScript表达式(变量){}。这个“标签状物体”就是被称之为虚拟DOM的那个东西,一直在讨论中。
只需调用一个 React 的 API,就是最后一个 ReactDOM.createRoot().render()。而且这是这篇文章中唯一涉及到的 React 的 API。只要需要显示数据,只要有这个就可以了。
也许有人在旧文章中看到过使用 class 構文(直到2019年)或使用 React.createClass API(直到2015年)来定义组件的内容,但这些已经成为了遗留的做法。现今,组件基本上是通过简单的函数来定义的。
一看就觉得它很像常用的服务器端语言中所谓的“模板”。但是与模板只是基于字符串的处理方法,并且需要进行HTML词法解析的过程不同,React则是基于称为“虚拟DOM”的两个“DOM设计图”来直接处理实际的DOM。像ItemList和ItemDetail这样的函数返回的“类似标签”的东西并不是真正的DOM元素,只是设计图,也就是非常轻量级的JavaScript对象。
在传统的模板引擎中,开发者需要学习引擎独有的模板语法(例如循环等),并编写模板文件。而在 React 中,开发者需要用 JavaScript 编写返回 DOM 设计图的函数。除了这种类似 HTML 标签的写法和 {} 中可以插入任意表达式之外,没有其他独有的规则。循环和条件分支只需要像平时在 JavaScript 中一样使用三元运算符和 Array.prototype.map 即可。
通过类似标签的描述(函数调用)创建虚拟 DOM 后,ReactDOM.render 会在指定位置构建相应的真实 DOM 元素。这样做的原因是为了使开发者不需要手动编写像 appendTo()、removeClass()、text()、val() 这样的 jQuery 类 DOM 操作。
React 是一个只做基本事情的库。嗯,你觉得没什么特别的吗?换句话说,它只是让以前在服务器端语言(比如 PHP 或 JSP)中使用的模板变得稍微麻烦一些。相较于模板,有什么值得高兴的地方呢?为什么有些人称它为一种能够彻底改变世界的力量呢?接下来我会解释。
原因:JSX很方便且安全。
既经过所见,React引入了被称为JSX的类HTML语法来编写JavaScript代码。这是因为仅仅使用普通的JavaScript语法来读写DOM的设计图对人类来说非常困难。虽然JavaScript语法非常适合描述类似JSON的数据,但是它无法高效地表示类似HTML/XML的数据结构,比如”元素有属性,并且子元素可以是文本节点或其他元素”。
在JSX/HTML/XML的语法中,可以通过`
`直观地表达结构。如果用JSON写的话,会变成`{ element: ‘div’, attributes: { title: ‘message’ }, children: [ ‘Hello ‘, { element: ‘b’, children: [‘World’] } ] }`。这样写不好。
当提及的“标签”通过Babel、TypeScript或CoffeeScript(>=2.0)等工具处理后,会机械地变成以下的形式。
React.createElement(
"div",
{ title: "message" },
"Hello ",
React.createElement("b", null, "World")
);
如果您想尝试,可以在 Babel 的 REPL 中进行各种尝试(请将react预设打开)。简而言之,Text 会被转换为类似于React.createElement(Element,{a:’b’,c:d},’Text’)的 JavaScript 代码3。该函数在执行时会输出类似于上述JSON的对象,这就是虚拟DOM的最终真身。因为只有这个功能,所以想要手写的人不必使用JSX,实际上,一些精通React的开发者可能不再需要JSX。本文将通过使用JSX来论证4。
只要有JSX语法,JavaScript从一开始就具备了古典模板引擎辛勤实现的循环、条件分支、子模板调用(函数调用)和数值计算等功能,而且还超级高效,所以没有理由不使用。
巴别(Babel)、esbuild、TypeScript和CoffeeScript都已经普遍支持JSX,如果对这些工具熟悉的话,引入JSX的门槛就会很低。JSX本身只是一种通用且非常便利的语法糖,因此在许多其他库中也被采用,并且在各种编辑器中受到了非常良好的支持。可以说,现在已经几乎成为了事实上的标准了。
大约在2015年之前,JSX语法的生态系统比较薄弱,React开发团队发布了专用的JSX转换工具。因此,偶尔还能看到”React与altJS不兼容”的文章。
使用慣用的模板与循环相比,循环的可读性稍微降低了一些,但简单的语法错误,例如标签的不匹配,在编译时会进行检查,并且几乎不会出现XSS漏洞,例如转义错误。如果使用TypeScript,还可以进行严格的类型检查。
JSX最初可能会感到不适,但实际上,它与当时XML更为流行时提出的E4X语法非常相似,而且已经在Firefox中得到了实现。在还没有JSON的年代,有人想象使用XML取代JSON的未来,并且在那个时代,就像使用双引号””将字符串字面量括起来一样,使用将XML字面量括起来并在JavaScript中编写是很自然的。如果了解这一点,JSX可能会被视为JavaScript的非常自然的扩展。
然后,让我们认为HTML和JavaScript的合并不仅仅是一个禁忌,而且是一个非常重要的优点。长时间以来,“分离HTML和JavaScript”一直都是一个铁规,因为HTML是一个能够独立存在的主要文档,通过服务器端在HTML中艰难嵌入实际数据,而JavaScript只是一个附加物的时代已经过去了。现在在SPA中,几乎所有的实际数据都通过API传送,并且所有内容都以动态方式构建,因此HTML部分逐渐变成了“空壳子”的静态展示场所,如“没有内容的
-
- ”、“等待变形成日历和滑块的
”、“与