問題:
React中點(diǎn)擊事件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>
)
}
}
一個(gè)方法incrementCounter寫了4個(gè)地方言疗,有人可能會做出以下優(yōu)化:
在渲染函數(shù)中添加一個(gè)匿名箭頭函數(shù),箭頭函數(shù)自動綁定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>
)
}
}
結(jié)果是短了岁忘,但是這么做有個(gè)致命的問題舵稠,每次渲染都會創(chuàng)建一個(gè)新的函數(shù),我們一個(gè)新的組件<MyCustomButton /> 可能被迫每次都重新渲染嗓违,除非你重寫了自己的shouldComponentUpdate
在代碼量和工程量小的項(xiàng)目中九巡,這沒有什么,當(dāng)復(fù)雜的大型項(xiàng)目中蹂季,這是致命的冕广。
解決方案
使用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.書寫少了,不需要在構(gòu)造函數(shù)中bind了
3.因?yàn)樽詣咏壎ǔソ啵瘮?shù)不會再次創(chuàng)建撒汉,子組件非常容易成為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} >點(diǎn)擊我</button>
</div>
)
}
}
class MyButton extends PureComponent {
render() {
console.log("PureComponent render...")
return (
<div>
<button onClick={this.props.onClicked} >點(diǎn)擊我</button>
</div>
)
}
}
const MyButton = ({
onClicked
}) => {
console.log("stateless function render...")
return (
<div>
<button onClick={onClicked} >點(diǎn)擊我</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} >點(diǎn)擊我</MyButton>
<h1>{this.state.counter}</h1>
</div>
)
}
}
export default App;
1.componet組件
- 每次點(diǎn)擊打印
component render...
- 按鈕組件渲染次數(shù)=點(diǎn)擊次數(shù)
-
沒有任何渲染優(yōu)化
image.png
2.PureComponent重載了shouldComponentUpdate,進(jìn)行shallowCompare優(yōu)化后
- 每次點(diǎn)擊不打印 PureComponent render...
-
按鈕組件渲染次數(shù)=0
image.png
3.stateless function
-
結(jié)果同component父能,只是可讀性更好神凑,但是渲染上并沒有發(fā)任何優(yōu)勢
image.png
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.
總結(jié)
如果沒有渲染上的影響,盡量使用stateless functional component何吝,畢竟可讀性好溉委。PureComponent可以優(yōu)化但是如果是可變的對象或者數(shù)組,注意淺比較易引起不刷新的bug.
參考:
public-class-fields
Stateful vs. Stateless Functional Components in React
Optimizing React Performance with Stateless Components