告别旧方式——jQuery 与 React
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

与普遍的看法相反,React 最大的应用场景并非单页应用(SPA),而是混合应用,混合应用才是最常见的,而且在我看来也是最合适的。在这篇文章中,我将讲述我如何以及为什么从 React 的反对者转变为 React 的粉丝,以及为什么 React 是 jQuery 的完美替代品。
React 和 Vue 刚开始流行并成为构建现代 UI 的事实标准时,我内心曾有过某种抵触情绪。
是的,我故意没有提到 Angular,尽管 AngularJS 是引领 Web 2.0 的前端革命的先驱。
Angular 在理念上完全相反,它是一个功能齐全的 SPA 框架,而 React 只是一个视图库,我仍然不认为 SPA 是正确的方法,我个人更喜欢混合方法。
对于现在可能在想“那 Vue 呢?”的各位,Vue 介于这两个极端之间。
与普遍认知相反,React 最大的应用场景并非单页应用(SPA),而是混合应用,在我看来,混合应用才是最常见、也最合适的应用场景。不信?看看 Facebook 的 Dan Abramov 怎么说:
有趣的是,React 与单页应用(SPA)联系如此紧密,但 Facebook 并没有将其用于 SPA(除了 Instagram 网站和一些内部工具)—— @dan_abramov
我最讨厌的事情之一就是 Webpack 以及他们自带的所有工具。
我强烈认为他们给前端引入了不必要的复杂性,没错,他们让我们这些开发人员感觉自己像火箭科学家一样,因为我们需要进行大量的调整,需要拉动和转动大量的杠杆和齿轮才能使它们运行,但归根结底,他们真的为业务增添了价值吗?
他们改进了产品和用户体验,是否值得付出更高的维护和开发成本以及更高的新手入门门槛?而我们完全可以用普通的 jQuery,甚至更好的原生 JS 来实现同样的功能。
在我发现 React 引入了 react-cli 之后,我决定再试一次,结果真是让我惊喜不已。
随着 react-cli(和 vue-cli)的推出,80-90% 的使用场景都无需再处理那些繁琐的工具和相当于获得计算机科学博士学位的构建步骤,尽管对于某些特殊情况,你仍然需要卷起袖子,摆弄 webpack。
当然,如果你要构建的东西比较简单,比如一个用 Ajax 提交的联系表单,或者其他完全不同但足够简单的东西,那么在我看来,使用原生 JavaScript 就足够了,没必要动用那些复杂的技术。你甚至可以用 jQuery,但在如今这个时代,真的没必要,不过那是另一个话题了。
保持简单—— 这应该始终是你的座右铭。
在这种情况下,如果你使用框架,90% 的代码都将用于框架的基础设施,剩下的才是你的实际逻辑。这完全是过度设计,引入了不必要的样板代码,增加了打包体积,直接影响性能。更大的打包体积意味着需要通过互联网传输更多的字节,所以你实际上是在损害业务,仅仅因为你想使用那个炫酷的新技术。
哦,你觉得那几毫秒无关紧要吗?要知道,它们累积起来会非常可观,尤其是在高流量网站上。虽然现在的机器性能强大,但这并不意味着我们可以肆意妄为,把所有东西都扔给它们,我们需要谨慎地使用资源。
这样想就好比你为一座十层楼房打好了地基,结果却在上面搭了个帐篷。
与传统方式相比,React 在构建复杂用户界面时真正展现出其优势。
使用 React,随着所构建 UI 的复杂性增加,开发的简易性也会增加;换句话说,与原生 JS/jQuery 方法相比,开发成本与复杂性成反比。
空谈无益,让我们通过一个现实世界的例子来实践一下。
我们有发票表格,除了发票日期、发票到期日、主题等一般数据外,用户还需要能够添加/删除发票项目。
另一方面,发票项目包含以下内容:
- 您所开具发票的产品/服务的名称和/或描述,
- 是数量问题,
- 价格,
- 您提供的任何折扣,
- 任何由此产生的罚息,
- 那么,根据您所在国家/地区的法律,我们可能需要缴纳增值税或销售税。
最后,还有与上述内容相关的所有计算。 现在你明白看似简单的事情很快就会变得复杂了吗?
用老方法,你得想很多事情,你需要:
-
在所有不同的输入字段上添加更改事件处理程序,其中一些还需要相互抵消,因此您需要跟踪何时分离它们。
-
每次添加或删除发票项目时,都需要操作 DOM,通过添加或删除子节点或将 HTML 编写为字符串来实现。
无论选择哪种方式,都需要拼接一些 HTML 代码并填充变量,这很快就会变得难以管理。ECMA 6 字符串字面量虽然能稍微简化这个问题,但仍然会很麻烦。
想象一下,如果设计师修改了某些东西,你需要修改多少个地方,才能修改你在原生 JS 代码中拼接在一起的所有部分?
你还需要记住一点:如果你把 DOM 作为字符串来操作,你会杀死所有相关 DOM 元素的事件处理程序。没错,又一个陷阱。
-
计算——每次添加或删除发票项目时,都需要计算其具体数值,并更新发票的小计、税额、总计等。实际上,您需要创建自己的状态存储。
我可能漏掉了一两件在用老方法处理这个用例时会遇到的问题,通常情况下,纸面上的一切听起来都很简单,直到你开始实施,才会出现一系列需要处理的新情况。
使用 React 需要你稍微转变一下思维方式。简而言之,你只需要关注一件事:状态。这极大地简化了逻辑,你只需要关注状态,这是你唯一需要操作的东西,发票输入字段和发票项目会根据状态的变化重新渲染。
让我们来看一个简化后的代码示例,这或许能让你更清楚地理解。
import React from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";
class InvoiceItemForm extends React.Component {
constructor(props) {
super(props)
this.state = {
itemInput: {
description: '',
quantity: 0,
price: 0,
subtotal: 0,
taxRate: 0.17,
tax: 0,
total: 0
},
invoiceItems: []
}
this.handleInputChange = this.handleInputChange.bind(this);
this.addItem = this.addItem.bind(this);
this.removeItem = this.removeItem.bind(this);
}
handleInputChange(e) {
let input = (e.target || e.currentTarget);
input.subtotal = input.price * input.quantity;
input.tax = input.subtotal * input.taxRate;
input.total = input.subtotal * (1 + input.taxRate);
this.setState((state) => { return state.itemInput[input.name] = input.value; });
}
addItem() {
let state = this.state;
state.items.push(state.itemInput);
// Clear the last input
for (let key in state.itemInput) {
switch (key) {
case 'description'
state.itemInput[key] = '';
break;
case 'taxRate':
state.itemInput[key] = 0.17;
break;
default:
state.itemInput[key] = 0;
break;
}
}
this.setState({itemInput: state.itemInput, items: state.items});
}
removeItem(e) {
let rowIndex = (e.target || e.currentTarget).parentNode.parentNode.rowIndex;
let items = this.state.items.filter((item, i) => { return i !== rowIndex; });
this.setState({items : items});
}
renderCells(item, rowIndex) {
let cells = [<td>{rowIndex + 1}</td>];
let i = 1;
for (let key in item) {
cells.push(<td key={i}>{item[key]}</td>);
i++;
}
cells.push(
<td>
<button onClick={this.removeItem}>
{'Remove Item'}
</button>
</td>
);
return cells;
}
render () {
return (
<React.Fragment>
<div>
<input
name={'description'}
value={this.state.itemInput.description}
onChange={this.handleInputChange} />
<input
name={'price'}
value={this.state.itemInput.price}
onChange={this.handleInputChange}>
<input
name={'quantity'}
value={this.state.itemInput.quantity}
onChange={this.handleInputChange}>
<input
name={'taxRate'}
value={this.state.itemInput.taxRate}
onChange={this.handleInputChange}>
<input
name={'subtotal'}
disabled={true}
value={this.state.itemInput.subtotal}
onChange={this.handleInputChange}>
<input
name={'tax'}
disabled={true}
value={this.state.itemInput.tax}
onChange={this.handleInputChange}>
<input
name={'total'}
disabled={true}
value={this.state.itemInput.total}
onChange={this.handleInputChange}>
</div>
<table>
<thead>
<tr>
<th>Item no.</th>
<th>Description</th>
<th>Price</th>
<th>Quantity</th>
<th>Tax Rate</th>
<th>Subtotal</th>
<th>Tax</th>
<th>Total</th>
<th></th>
</tr>
</thead>
<tbody>
{
this.state.items.map((item, i) => {
return (
<tr key={i}>
{this.renderCells(item, i)}
</tr>
);
})
}
</tbody>
</table>
</React.Fragment>
);
}
}
export default InvoiceItemForm
Vuoala,就是这样!
嘿,你是不是想迁移一个 jQuery 应用?或者你只是在为你的下一个百万美元创意寻找最佳框架?请联系我们info@jsguru.io,让我们来帮你解决这些难题。
在你离开之前……
如果您喜欢这篇文章,请分享。也欢迎浏览我们的其他文章,您或许也会感兴趣!我们会不定期撰写关于软件开发、技巧秘诀以及如何成为更优秀的开发者和商业人士的文章。加入我们,一起不断进步吧!
请在Facebook、Twitter、LinkedIn、Medium或DEV.to上关注我们。
原文发表于jsguru.io。
文章来源:https://dev.to/jsguru_io/leaving-the-old-ways---jquery-vs-react-4f69
