React 在 16.3 版新增了一些新的生命週期方法,並開始逐漸廢棄一些舊方法,舊方法就是前一篇提過的componentWillMount()
componentWillReceiveProps()
componentWillUpdate()
新增的生命週期方法則是以下這幾個getDerivedStateFromProps
getSnapshotBeforeUpdate
這一篇會針對整個生命週期和新版方法做整理。
constructor(props)
並生成實例, props
就是元件的父層傳遞來的參數。同時元件也會藉由 super()
去繼承一些 React.Component
的屬性和方法。如下面的範例, Input
元件中的 constructor(props)
,props
裡面的參數就是 Form
傳入的參數,而使用 super()
後,this
會指向 Input
本身。不過使用 constructor()
的麻煩就是你的屬性、函式都得在裡面定義。在一些框架中如 create-react-app 中是可以在 class
中直接定義屬性和函式而不必透過 constructor()
。class Form extends React.Component {
state = {
value: '123'
}
onEditer (value) {
this.setState({value})
}
render () {
const { value } = this.state
return <div>
{value}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
class Input extends React.Component {
constructor (props) {
super() // 改變 this 的指向為這個元件
console.log(props) // props 就是 Form 元件傳進來的物件,裏面包含了 value、
}
render () {
const { onEditer } = this.props;
return <div>
<input type="text" onChange={e => onEditer(e.target.value)} />
</div>
}
}
constructor()
執行完畢後就會接著執行 getDerivedStateFromProps()
,或者是元件有更新時,像是 props
、state
更新,或者 forceUpdate()
執行,都會觸發這個方法。getDerivedStateFromProps()
是一個靜態方法,必須搭配 static
使用,它接受兩個參數,props
、state
,我們可以透過這個方法,去監聽這兩個參數,執行一些事情。getDerivedStateFromProps()
最後必須返回一個物件或是 null 值,如果返回物件,則依照物件內的屬性來更新 static
。class Form extends React.Component {
state = {
value: 'leo'
}
onEditer (value) {
this.setState({value})
}
render () {
const { value } = this.state
return <div>
{value}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
class Input extends React.Component {
state = {
value: 'jack'
}
static getDerivedStateFromProps(props, state) {
if (props.value !== state.value) {
return {
value: props.value,
age: 26 //這邊新增一個 age 屬性,也會增加在 state 裡面
}
}
return null
}
render () {
console.log(this.state) // value: leo, age: 26
const { onEditer, value } = this.props;
return <div>
<input type="text" value={value} onChange={e => onEditer(e.target.value)} />
</div>
}
}
getDerivedStateFromProps()
執行完後,就接著執行 render
渲染整個元件。render
執行完後,表示我們已經有了整個 DOM 結構,這時候才輪到 componentDidMount
執行,而且只會在整個結構第一次渲染完成的這一次執行。componentDidMount
沒有任何參數,一般會在這個方法中去執行數據的請求。class UserProfile extends React.Component {
state = {
user: null
}
//在 componentDidMount 中進行非同步請求,並更新 state
async componentDidMount() {
const user = await fetch('/api/user').then(res => json());
this.setState({ user })
}
render () {
const { user = {} } = this.state;
return <div>
name: {user.name}
</div>
}
}
props
、state
更新,或者 forceUpdate()
執行,都會觸發這個方法。shouldComponentUpdate()
接在 getDerivedStateFromProps(props, state)
之後執行,主要是藉由返回 Boolean
來判斷是否更新元件,避免一些不必要的更新。不過 React 官方不建議使用這個方法,而是建議使用 PureComponent
,因為 PureComponent
也會避免不必要的更新。class UserProfile extends React.Component {
state = {
name: 'leo',
age: 20
}
changeVlue (state) {
return new Promise((resolve) => {
this.setState(state, resolve)
})
}
async changeData () {
const { age } = this.state
await this.changeVlue({age: age + 1})
}
shouldComponentUpdate () {
if (this.state.age > 26) { //當 age 大於 26,return false,停止更新
return false
}
return true
}
render () {
const { name, age } = this.state;
return <div>
{name} {age} 歲
<button onClick={this.changeData.bind(this)}>+1</button>
</div>
}
}
getSnapshotBeforeUpdate
是在 render
執行後,DOM
和 refs
更新前所做的事情,這可以讓我們在 DOM
變化前獲取一些訊息,例如畫面滾動之類的。如果在 getSnapshotBeforeUpdate
中返回值,生命週期會讓這個值作為參數傳遞給 componentDidUpdate()
。props
(prevProps)、更新前的 state
(prevState)、以及 getSnapshotBeforeUpdate
返回的參數。componentWillMount()
是卸載階段唯一的方法,是在元件卸載前執行,我們可以在這邊處理一些不必在執行的功能,避免過度使用記憶體,例如計時器功能。componentDidCatch()
是在元件有錯誤時候會執行。defaultProps
用於定義 props
的默認屬性,可以用在定義 undefined
的 props
,但不適用於 null
。有分外部定義及內部定義兩種,外部定義用法如下,利用 compnentName.defaultProps
來定義默認屬性,當沒有外部屬性傳入,就使用默認屬性。class Form extends React.Component {
state = {
value: 'leo'
}
onEditer (value) {
this.setState({value})
}
render () {
const { title } = this.props //'測試用 input'
const { value } = this.state
return <div>
{value}
{title}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
// 外部定義 default
Form.defaultProps = {
title: '測試用 input'
}
內部定義則是直接使用 static defaultProps
來定義
class Form extends React.Component {
state = {
value: 'leo'
}
static defaultProps = { //由於 defaultProps 是靜態方法,必須搭配 static 使用
title: '默認 props'
}
onEditer (value) {
this.setState({value})
}
render () {
const { title } = this.props
const { value } = this.state
return <div>
{value}
{title}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
當內部外部都有定義 defaultProps
時候,只會執行外部定義,而會忽略內部定義。
2. forceUpdate()forceUpdate()
這個方法會強制渲染 React 元件,包含子元件也會重新渲染,使用方式是直接調用,如下
class App extends React.Component {
componentDidMount () {
this.forceUpdate();
}
}
這一篇我們整理了新版 React 生命週期方法,到這篇為止,算是把 React 中的一些基礎概念整理完畢,下一篇開始,將會進行一些實作練習。