【React性能优化】 React组件优化
简介:
1.组件内: 传递参数的时候要少传,且每次传递的尽量是一份数据,不要每次这个数据都会被重新创建 2.组件间:shouldComponent、pureComponent、immutable
单组件 - 属性传递优化
- 函数绑定优化 - 绑定函数的几种方式
handleClick(event){ // 你的事件处理逻辑 } 1. onclick={::this.handlerClick} 不建议,es7中的写法,等同于3 onClick={this.handleClick.bind(this)} // 箭头函数中的上下文是所在全局的上下文,不决定于谁调用他 2. onclick={() => this.handlerClick()} onClick={this.handleClick} handleClick = () => { console.log(this); } // 所以我们需要在class的construct中将函数的执行作用域设为当前组件 3. constructor(props, context) { super(props, context) this.handlerClick= this.handlerClick.bind(this) } onclick={this.handlerClick}
Q: 上面那种方式最好?
构造函数bind > 箭头函数 > 直接bind 因为构造函数只会在app创建,执行一次,箭头函数和bind每次都返回一个新的函数,引起渲染
Q: React事件机制,为什么拿不到this
class Foo { constructor(name){ this.name = name } display(){ console.log(this.name); } } var foo = new Foo('Saurabh'); foo.display(); // Saurabh //下面的赋值操作模拟了上下文的丢失。 //与实际在 React Component 中将处理程序作为 callback 参数传递相似。 // 类声明和类表达式的主体以 严格模式 执行,主要包括构造函数、静态方法和原型方法。Getter 和 setter 函数也在严格模式下执行。 var display = foo.display; display(); // TypeError: this is undefined
Q:为什么在使用bind能解决
// 解决:构造函数中bind,对应第三种方法 class Foo { constructor(name){ this.name = name this.display = this.display.bind(this); } display(){ console.log(this.name); } var foo = new Foo('Saurabh'); foo.display(); // Saurabh var display = foo.display; display(); // Saurabh // 我们也可以在其他地方bind,对应第一种方法 // 但由于构造函数是所有初始化发生的地方,因此它是编写绑定事件语句最佳的位置 class Foo { constructor(name){ this.name = name; } display(){ console.log(this.name); } } var foo = new Foo('Saurabh'); foo.display = foo.display.bind(foo); foo.display(); // Saurabh var display = foo.display; display(); // Saurabh
Q:箭头函数为什么能解决
1.箭头函数机制
箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。 这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this this 是有词法约束力的。这意味它可以使用封闭的函数上下文或者全局上下文作为 this 的值
2.分析为什么能解决 - 箭头函数两种解决方式
公共类字段语法: 箭头函数被包含在 Foo 类中或者构造函数中,所以它的上下文就是组件实例
class Foo extends React.Component{ handleClick = () => { console.log(this); } render(){ return ( <button type="button" onClick={this.handleClick}> Click Me </button> ); } } ReactDOM.render( <Foo />, document.getElementById("app") );
回调中的箭头函数:箭头函数被包含在 render() 方法中,该方法由 React 在组件实例的上下文中调用
class Foo extends React.Component{ handleClick(event){ console.log(this); } render(){ return ( <button type="button" onClick={(e) => this.handleClick(e)}> Click Me </button> ); } } ReactDOM.render( <Foo />, document.getElementById("app") );
Q: bind为何不能用 call和apply这种替代
因为call和apply会立即执行,这是bind与call,apply的区别
2.传递参数注意
如果直接写一个对象在item处,则每次会生成新的
so, 传递参数的时候要少传,且每次传递的尽量是一份数据,不要每次这个数据都会被重新创建
const item = { firstName: 'Liu' } <Demo style={{ color: 'red' }} name={item}></Demo> <Demo {...this.state}></Demo>
多组件优化
1.shouldComponentUpdate
// 浅比较前后两次的props的变化 // 一般redux的state层次深,数据结构复杂,深层比较太消耗性能,得不偿失 class Demo extends React.component { shouldComponentUpdate(nextProps, nextState) { if (compareObj(nextProps, this.props)) { return false } return true } render() { return <h2>{this.props.title}</h2> } }
浅比较
function compareObj(obj1, obj2) { if (obj1 == obj2) { return true } if (Object.keys(obj1).length !== Object.keys(obj2).length) { return false } for(let k in obj1) { if (obj1[k] !== obj2[k]) { return false } } return true }
补充: 深比较的实现 - 浅比较的递归
function compareObj(obj1, obj2) { if (obj1 == obj2) { return true } if (Object.keys(obj1).length !== Object.keys(obj2).length) { return false } for (let k in obj1) { if (typeof obj1[k] == 'object') { return compareObj(obj1[k], obj2[k]) } else if (obj1[k] !== obj2[k]) { return false } } return true }
React16 简易的写法 - 把nextProps每个都遍历比较了一遍
class Demo extends React.PureComponent { render() { return <h2>{ this.props.title }</h2> } }
2. immutablejs
解决什么问题:
immutablejs的出现就是为了解决可变数据结构深层比较的性能问题 让我们更优更高效的比对数据,减少渲染
优势:
节省内存,降低可变的风险,可以用等号判断是否相等 比较是直接拿地址得hash做对比,所以比较相等的复杂度特别低
使用:
将react, redux的数据全部改为使用immutable的数据类型来操作
// 此时,定制shouldComponentUpdate就会特别简单高效 class Demo extends React.component { shouldComponentUpdate(nextProps, nextState) { return is(nextProps, this.props) } render() { return <h2>{this.props.title}</h2> } }
推荐immutable轻量级包:seamless-immutable
Key
建议:循环时,不要使用index来作为key,最好拿数值或者数组与其他的组合来确保key的唯一性
<ul> {this.state.users.map((v,index) => <li key={index}>{v}</li>)} </ul>
问题:
如果我再数组前面插入数组,则整个数组的index都会发生变化,v-dom就没有存在的意义 key用来标识同级的dom元素,其作用和重要性,详情请见另一篇blog - 深入diff和虚拟dom key变化了,react比对时,就会全部删除插入,不会进行复用移动
相关推荐
81417707 2020-10-30
iftrueIloveit 2020-07-04
80981934 2020-05-18
游走的豚鼠君 2020-11-10
ctg 2020-10-14
小飞侠V 2020-09-25
PncLogon 2020-09-24
jipengx 2020-09-10
颤抖吧腿子 2020-09-04
wwzaqw 2020-09-04
maple00 2020-09-02
青蓝 2020-08-26
罗忠浩 2020-08-16
liduote 2020-08-13
不知道该写啥QAQ 2020-08-02
pengruiyu 2020-08-01
wmd看海 2020-07-27
孝平 2020-07-18