问题:
React中点击事件onClick中需要访问this,一般代码是:
class App extends Component {
state = {counter: 0}
constructor() {
super()
// Like homework or situps; something you have to do :(
this.incrementCounter = this.incrementCounter.bind(this)
}
incrementCounter() {
this.setState(ps => {
return {counter: ps.counter + 1}
})
}
render() {
return (
<div>
<p>
<button onClick={this.incrementCounter}>Increment</button>
</p>
<h1>{this.state.counter}</h1>
</div>
)
}
}
一个方法incrementCounter写了4个地方,有人可能会做出以下优化:
在渲染函数中添加一个匿名箭头函数,箭头函数自动绑定this
class App extends Component {
state = {counter: 0}
render() {
return (
<div>
<p>
<button onClick={() => {
this.setState(ps => {
return {counter: ps.counter + 1}
})
}}>Increment</button>
</p>
<h1>{this.state.counter}</h1>
</div>
)
}
}
结果是短了,但是这么做有个致命的问题,每次渲染都会创建一个新的函数,我们一个新的组件<MyCustomButton /> 可能被迫每次都重新渲染,除非你重写了自己的shouldComponentUpdate
在代码量和工程量小的项目中,这没有什么,当复杂的大型项目中,这是致命的。
解决方案
使用Babel的 public class field
class App extends Component {
state = {counter: 0}
incrementCounter = () => {
this.setState(ps => {
return {counter: ps.counter + 1}
})
}
render() {
return (
<div>
<p>
<button onClick={this.incrementCounter}>Increment</button>
</p>
<h1>{this.state.counter}</h1>
</div>
)
}
}
1.绑定了this
2.书写少了,不需要在构造函数中bind了
3.因为自动绑定,函数不会再次创建,子组件非常容易成为PureComponent
测试
整体例子代码
import React, { Component, PureComponent } from 'react';
import logo from './logo.svg';
import './App.css';
import Perf from 'react-addons-perf'
window.Perf = Perf
class MyButton extends Component {
render() {
console.log("component render...")
return (
<div>
<button onClick={this.props.onClicked} >点击我</button>
</div>
)
}
}
class MyButton extends PureComponent {
render() {
console.log("PureComponent render...")
return (
<div>
<button onClick={this.props.onClicked} >点击我</button>
</div>
)
}
}
const MyButton = ({
onClicked
}) => {
console.log("stateless function render...")
return (
<div>
<button onClick={onClicked} >点击我</button>
</div>
)
}
class App extends Component {
state = {
counter: 0
}
onClickedMe = () => {
this.setState(ps => {
return {
counter : ps.counter + 1
}
}
)
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<MyButton onClicked={this.onClickedMe} >点击我</MyButton>
<h1>{this.state.counter}</h1>
</div>
)
}
}
export default App;
1.componet组件
- 每次点击打印
component render...
- 按钮组件渲染次数=点击次数
-
没有任何渲染优化
2.PureComponent重载了shouldComponentUpdate,进行shallowCompare优化后
- 每次点击不打印 PureComponent render...
-
按钮组件渲染次数=0
3.stateless function
-
结果同component,只是可读性更好,但是渲染上并没有发任何优势
It should be noted that stateless functional components don't have the upper hand in terms of optimization and performance because they don't have a ShouldComponentUpdate() hook. This might change in future versions of React, where functional components might be optimized for better performance. However, if you're not critical of the performance, you should stick to functional components for the view/presentation and stateful class components for the container.
总结
如果没有渲染上的影响,尽量使用stateless functional component,毕竟可读性好。PureComponent可以优化但是如果是可变的对象或者数组,注意浅比较易引起不刷新的bug.
参考:
public-class-fields
Stateful vs. Stateless Functional Components in React
Optimizing React Performance with Stateless Components