需求什么的停一停,我们来填一部分前面的坑。
React 的优势
又名:我为什么要学 React?React 牛逼在哪里?jQuery不是用的挺好吗?……
好处众说纷纭,我们来看一眼 React 官网首页给出的特性:
-
Declarative
React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
Declarative views make your code more predictable and easier to debug. -
Component-Based
Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM. - 一些其他我们现在不用关心的东西。
大部分优势已经很清楚了,不过 efficiently update and render 是怎么回事?
Virtual DOM
以上一篇案例中的列表来说,我们使用一个数组,存储了列表中所有需要显示的数据,当我们直接使用 JS 实现时,数据可能是下面这样:
var itemList = [{barcode:'ITEM000000',...},{barcode: 'ITEM000001'...},...];
如果,列表中的数据前后位置发生变化,比如,用户希望把优惠信息较多的商品显示在前面。emmm. 那我们就需要把 itemList
中的所有元素,按照这个规则进行排序,再使用排序后的数据,重新渲染整个页面。
sortWithPromotions(itemList);
itemListView.innerHTML = listToDOM(itemList);
这个 DOM 操作,貌似并没有花费掉多少运算能力。但是,朋友,DOM操作是很慢的。当页面中变动的元素数量稍稍多点的时候,就比较可怕了。
看一眼优惠信息:
barcodes: ['ITEM000000', 'ITEM000001', 'ITEM000005']
如果按照有优惠就在前的规则排序,仅仅需要交换ITEM000002
和 ITEM000005
的位置就可以了。之前在 key
中也提到过,React 会高效的处理和渲染列表中的动态数据。
当页面中的数据发生变动时,React 并不会重新渲染 整个页面,而是在自己生成的 Virtual DOM 中,进行数据修改。再将 Virtual DOM 和真正的 DOM 做 对比,找出 发生变动的部分,并只将这部分内容渲染到页面中去。
听起来很有道理,而且听起来像骗人的,技术发展这么多年了,非要一直到 React 里才出现这种比对思想吗?而且,明明在操作原生 DOM 前还操作了虚拟 DOM,还做了对比,这难道真的还要比直接操作原生 DOM 效率要更高吗?
第一个问题,难点在比较两棵 DOM 树差异的 diff 算法的效率问题。
第二个问题,并不。只是在 React 中生成 Virtual DOM 、进行 diff 、渲染差异部分优化后的总时间,仍然比直接重新渲染整个页面的原生DOM操作时间少。当某天直接操作原生DOM够快时,那我们或许就不再需要 Virtual DOM 了。
setState
接下来,我们对之前的Counter
做一个小小的改动,在点击事件中,count自增1之后,再立即自增1。
handleCountIncrease(event) {
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
}
点击一次后,可以看到Counter
中显示的还是1。
之前我们并没有在点击事件中的处理方法中直接使用过这个值,所有到此为止并没有出什么问题。然而,可以感受到第二次自增中的 count
的值还没有变为1。如果count
的默认值为0,相当于,我们将 count = 0 + 1
执行了两次。
为了提高性能,React 会 批量处理 state
的变更,而不是在发生一处改变之后就立即处理。这就会带来 异步 问题。如果需要立即使用这个值进行计算,可以把第二次需要立即使用state
值的自增操作改为:
this.setState((prevState) => ({
count: prevState.count + 1
}));
下面的写法效果是一样的:
this.setState(function(prevState) {
return {
count: prevState.count + 1
};
});
propTypes
习惯了强类型语言,JS中对于类型的处理让我一直很不习惯。
抛去其他不说,在之前的组件<Item/>
中,我们需要在使用时传入一个 Item 对象用于页面渲染。问题是使用这个组件的人,可能会随便传进来一个什么奇怪的东西,并且编译器也不会帮你检查,真是一点办法都没有。
emmm,其实是有办法的。
我们可以使用prop-types
库来限定每一个传入数据props
的类型,安装一下。
npm install prop-types
比如最简单的限制item的类型为object,给Item.js
稍稍增加一点代码:
import PropTypes from 'prop-types'
...
static propTypes = {
item : PropTypes.object.isRequired
}
像代码里说的那样,我们在Item
组件中要求item
的类型为object,写法和设置默认值差不多。这样的类型以及不同的限定方式还有很多,可以在这里找到。
当我们传一个字符串'item'
进去的时候,在控制台很容易找到问题:
今天就到这里了。
网友评论