简介:
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比对时,就会全部删除插入,不会进行复用移动