【翻译】jQuery和React.js的思考

原文链接: jQuery versus React.js thinking

本质上,我不喜欢辩论技术之间的好坏。我认为每一个相当成功的库或者框架在它刚开始推出来到成功都是有很好的理由的。我将会从概念上来比较jQuery和React的不同。

##问题
一组列表。每一项都有一个默认隐藏的详细信息。任何时候,用户点击列表中的一项,那一项都会展开并且展示它的详细信息,其它项将会变成灰色。如果我们再次点击同一项,它将会收缩并且所有项都会变成它们的初始状态,折叠的并且字体变成黑色的。我们也可以从一个展开的项转移到另一项,折叠前一项,展开新的那项。

##两种解决方法

###jQuery(JSBin)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$(function() {
$('li').on('click', function(e) {
var $clickedItemDetails = $(e.currentTarget).find('.details');
var $allDetails = $('li .details');
if ($clickedItemDetails.is(':hidden')) {
$allDetails.hide().parent().removeClass('collapsed');
$clickedItemDetails.show();
} else {
$clickedItemDetails.hide();
}
$allDetails.each(function(index, el) {
if ($(el).is(':hidden')) {
$(el).parent().addClass('collapsed');
}
});
if ($('li.collapsed').length === $('li').length) {
$('li').removeClass('collapsed');
}
});
});

我们的数据和它的状态不是有组织化的,并且分布在DOM中。数据、状态和展示的分隔是模糊的。

我们用jQuery的选择器(类似:is(':hidden').find('.details'))从DOM中查找数据。然后我们用hide(),show(),addClass()removeClass()函数直接在DOM上修改状态。

在最开始的时候,我这样子写过一些代码,现在回过来想读它的时候,我需要整理下思绪来重新读懂它。因为功能是如此的有限所以我可以不用破坏它的代码就能重构,但是当我想给它添加更复杂的功能的话将不会是件容易的事。

###React(JSBin)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/** @jsx React.DOM */
var PRODUCTS = [
{
"id": 1, "name": "Bag of suck", "price": 100,
"details": "You don't want to own this!"
},
{
"id": 2, "name": "Bag of luck", "price": 200,
"details": "You might want to own this!"
},
{
"id": 3, "name": "Bag of fuck", "price": 300,
"details": "You really want to own this!"
}
];
var ItemsList = React.createClass({
getInitialState: function() {
return {
expandedProductId: null
};
},
handleProductClick: function(product) {
var newSelectedProductId = product.id;
if (this.state.expandedProductId === product.id) {
newSelectedProductId = null;
}
this.setState({expandedProductId: newSelectedProductId});
},
render: function() {
var self = this, noneSelected = this.state.expandedProductId === null;
var products = PRODUCTS.map(function(product) {
var details, isExpanded = self.state.expandedProductId === product.id;
if (isExpanded) {
details = <div>{product.details}</div>;
}
return (
<li key={product.id}
onClick={self.handleProductClick.bind(self, product)}
className={isExpanded || noneSelected ? '' : 'collapsed'}>
{product.name} ({product.price})
{details}
</li>
);
});
return (
<ul>
{products}
</ul>
);
}
});
React.render(<ItemsList />, document.body);

我最开始反应“哇,更多的代码,感觉更糟了”,但是没有,为什么呢?

  • 数据非常好地在PRODUCTS数组中隔离开。
  • 所有的状态我们都存储在expandedProductId
  • 所有的表现逻辑都写在render方法中。
  • 我们可以从上到下读取代码。
  • 快速地浏览后,我可以轻易的理解它做的所有事(你也许还不知道React,但是它非常容易学习)。

##结论
我知道这是个相当微不足道的例子。但是它确实显示了不同库(框架)之间根本上的不同,并且它们是怎样帮助你隔离关注点。