每个项目产品都要加埋点,加500行埋点是不是会占用你一两天的时间而且很容易犯错,想只用一小时准确加完这500行埋点剩下一天喝茶聊天么?来试试这520web工具, 高效加埋点,目前我们公司100号前端都在用,因为很好用,所以很自然普及开来了,推荐给大家吧
自己开发所以免费,埋点越多越能节约时间,点两下埋点就加上了,还不会犯错,里面有使用视频,反正免费 😄
一、优化原理
改写react生命周期shouldComponentUpdate,使其在需要重新渲染当前组件时返回true,否则返回false。不再全部返回true。
二、主流优化方式
1.react官方解决方案
原理:重写默认的shouldComponentUpdate,将旧props、state与新props、state逐个进行浅比较(形如:this.props.option === nextProps.option ? false : true),如果全部相同,返回false,如果有不同,返回true。
PureRenderMixin(es5):
var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
mixins: [PureRenderMixin],
render: function() {
return <div className={this.props.className}>foo</div>;
}
});
Shallow Compare (es6):
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>
}}
es7装饰器的写法:
import pureRender from "pure-render-decorator"
...
@pureRender
class SampleComponent extends Component {
render() {
return (
<div className={this.props.className}>foo</div>
)
}
}
react 15.3.0+写法(用来替换react-addons-pure-render-mixin):
class SampleComponent extends React.PureComponent{
render(){
return(
<div className={this.props.className}>foo</div>
)
}
}
*上述方案存在问题(浅比较的问题):
(1)某些props、state值未改变的情况,返回true,例如:
<Cell options={this.props.options || [ ]} />
当this.props.options == false时,options=[ ]。当父组件两次渲染,this.props.options一直 == false,对于Cell组件来说,options没有改变,不需要重新渲染。但Cell的shouldComponentUpdate中进行的是浅比较,由于[ ] !== [ ],所以,this.props.options === nextProps.options为false,shouldComponentUpdate会返回true,Cell将进行重新渲染。
解决方法如下:
const default = [ ];
<Cell options={this.props.options || default} />
(2)某些props、state值改变的情况,返回false,例如:
handleClick() {
let {items} = this.state;
items.push('new-item') ;
this.setState({ items });
}
render() {
return (
<div>
<button onClick={this.handleClick} />
<ItemList items={this.state.items} />
</div>
)}
如果ItemList是纯组件(PureComponent),那么这时它是不会被渲染的。因为尽管this.state.items的值发生了改变,但是它仍然指向同一个对象的引用。
2.Immutable
原理:Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。
Immutable Data就是一旦被创建,就不能再更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。同时,为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
【在react中使用immutable】
改变shouldComponentUpdate的重新渲染规则
(1)防止每次setState或传递props,即使state和props的值没有发生改变也重新渲染组件,带来无谓的性能消耗
(2)防止浅比较带来的比较误差问题,以及深比较带来的性能消耗问题。
import { is, fromJS } from 'immutable';
constructor(){
this.state = {
person: fromJS({
name: 'xuxuan',
age: 12
});
}
}
componentDidMount(){
this.setState({
person: this.state.person.update('name', v => v + 'update')
});
}
shouldComponentUpdate: (nextProps, nextState) => {
return !(this.props === nextProps || is(this.props, nextProps))
||
!(this.state === nextState || is(this.state, nextState));
}
【!!注意】state 本身必须是普通对象,但是里面的值可以是 immutable 的数据。
this.state和nextState是两个普通对象,通过is方法判断二者的值是否相同。
【从setState到re-render整个过程】(个人理解)
(1)setState中设置person的name值,由于person是immutable的,因此,这里会开辟一块新的内存,存储设置后的name(即使name的值没有真的发生改变,只要对immutable数据进行了设置操作,就会生成一个全新的对象),同时,开辟新内存,存储受name影响的immutable的各级父节点,这里只有person。而,其余未受影响的节点,将进行内存共享,如这里的age。由此,形成了新的state对象,即:nextState。
(2)setState(nextState)操作触发shouldComponentUpdate生命周期执行。
(3)shouldComponentUpdate中使用immutable.js的is方法对比两个对象。
这里,is采用hashCode和valueOf对比两个对象是否相同:
*当对象的值没有改变,is返回true,组件不重新渲染。依然存储旧的state(nextState大概会被销毁吧)
*当对象的值发生改变,is返回false,组件重新渲染。nextState替换state(state就不能再访问了,但它的immutable的属性应该还可以)
(4)当需要重新渲染的时候,对于state来说,就是用新的nextState替换旧的state。由于state是普通对象,因此可以被更改,被替换。
【关于is方法】
Immutable的is比较的是这个对象hashCode和valueOf,只要两个对象的hashCode相等,值就是相同的,避免了深度遍历,提高了性能。
扩展:
hashCode的比较是将两个对象String化(eg:{a:111} —> '{a:111}')后,比较两个字符串对应位置字符的charCode是否相同,完全相同则认为是两个相同的对象。
使用 Immutable 后,如下图,当红色节点的 state 属性值变化后,
Immutable数据树结构变化示意图
【注】
整棵树就是一个Immutable的对象。
当红色节点发生改变,为这个节点及其父节点开辟新的内存,存储新数据,其他蓝色节点不变,共享之前的内存。
immutable.js框架是非常好的Immutable库,其他可用api,详见官方文档。
使用原则:
由于侵入性较强,新项目引入比较容易,老项目迁移需要谨慎评估迁移成本。对于一些提供给外部使用的公共组件,最好不要把Immutable对象直接暴露在对外的接口中。
【!!Mark】
个人理解部分,如有理解偏差,请指正,感谢。
作者:南慕瑶
链接:https://www.jianshu.com/p/4dfdf0a412ed
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。