@duanyubin
2016-04-26T01:58:02.000000Z
字数 2894
阅读 525
javascript
React abstracts away the DOM from you, giving a simpler programming model and better performance.
在内存中,通过比较更新js object来更新dom,而不是直接操作dom。
此过程发生在render函数执行之后。
但是存在一个问题:
this.state = {count: 0}
this.setState({count: 0});// 组件 state 并未被改变,但仍会触发 render 方法
shouldComponentUpdate: function(nextProps, nextState) {
return true;
}
频繁执行此函数,默认返回true
, 若返回true
则执行render
方法
尽量保证shouldComponentUpdate
实现简单,执行快速
// typeof value === 'string'
shouldComponentUpdate: function(nextProps, nextState) {
return this.props.value !== nextProps.value;
}
var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
mixins: [PureRenderMixin],
render: function() {
return <div className={this.props.className}>foo</div>;
}
});
// OR
import PureRenderMixin from 'react-addons-pure-render-mixin';
class FooComponent extends React.Component {
constructor(props) {
super(props);
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
}
render() {
return <div className={this.props.className}>foo</div>;
}
}
// Shallow Compare
var shallowCompare = require('react-addons-shallow-compare');
export class SampleComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
render() {
return <div className={this.props.className}>foo</div>;
}
}
两者都是浅比较,如果更深层次的值发生了变化就会失效
如果深层的值发生变化,例如点击下列链接JS BIN 1中的 SetToSameCount ,会发现 render times 没有变化(预期效果),再点 SetToSameSchool ,render times 增加了(非预期效果,因为任何的state都没有改变)
这是由于js中两个object比较,比较的是引用,而string比较,则比较的是值
var a = 'a'
var b = 'a'
a === b // true
var c = {c: 1}
var d = {c: 1}
c === d // false
解决这个问题,就需要深层比较, 但是深层比较比较费时,效率低,违背了之前保证scu函数简单的原则,因此引入Immutable.js
假如我们要修改左图中黄色节点的子节点4,那么Immutable.js只需要更新右图中的绿色节点,其余节点不需拷贝,继续复用。也就是说,Immutable.js会更新从根节点到所修改节点路径上的所有节点,由于修改了根节点,所以返回一个新对象。
内部采用类似链表的实现方式,避免了局部更新造成的深拷贝的消耗
用immutablejs 改造上述例子JS BIN 2
点击中SetToSameCount和SetToSameSchool,会发现 render times都没有发生变化
Javascript中对象都是参考类型,可变的好处是节省内存或是利用可变性做一些事情,但是,在复杂的开发中它的副作用远比好处大的多
a = {a:1}
b = a
b.a = 2
a.a === 2 // true
//-----
option = {a:1}
function a(opt){opt.a = 2}
a(option)
option.a === 2 // true
例如,在JS BIN 1中,在输入框中high school name,会覆盖掉middle school name, 而在JS BIN 2中,由于每次改变之后,都是生成的新变量,就不会出现上述问题
function touchAndLog(touchFn) {
let data = { key: 'value' };
touchFn(data);
console.log(data.key); // 猜猜会打印什么?
}
在不知touchFn代码的情况下,不敢随意使用data,因为它有可能被修改
Immutable.js 使用了 Structure Sharing 会尽量复用内存。
import { Map} from 'immutable';
let a = Map({
select: 'users',
filter: Map({ name: 'Cam' })
})
let b = a.set('select', 'people');
a === b; // false
a.get('filter') === b.get('filter'); // true
Immutable 本身就是函数式编程中的概念,纯函数式编程比面向对象更适用于前端开发。因为只要输入一致,输出必然一致,这样开发的组件更易于调试和组装。
===
比较的是内存地址
let map1 = Immutable.Map({a:1, b:1, c:1});
let map2 = Immutable.Map({a:1, b:1, c:1});
map1 === map2; // false
Immutable.is(map1, map2); // true
map1.equals(map2); // true
Immutable.is
比较的是两个对象的hashCode
或valueOf
(对于 JavaScript 对象)。由于 immutable 内部使用了 Trie 数据结构来存储,只要两个对象的hashCode
相等,值就是一样的。这样的算法避免了深度遍历比较,性能非常好。