在本節(jié)中,我們將學(xué)習(xí)如何重用和封裝一個 Clock 組件。它將設(shè)置自己的計時器,并每秒鐘更新一次。
我們可以從封裝時鐘開始:
class Clock extends Component {
render () {
return (
<View>
<Text>Hello, world!</Text>
<Text>現(xiàn)在的時間是 {this.state.date.toLocaleTimeString()}.</Text>
</View>
)
}
}
Clock 現(xiàn)在被定義為一個類,使用類就允許我們使用其它特性,例如局部狀態(tài)、生命周期鉤子。
首先,我們需要添加一個類構(gòu)造函數(shù)來初始化狀態(tài) this.state:
class Clock extends Component {
constructor (props) {
super(props)
this.state = { date: new Date() }
}
render () {
return (
<View>
<Text>Hello, world!</Text>
<Text>現(xiàn)在的時間是 {this.state.date.toLocaleTimeString()}.</Text>
</View>
)
}
}
注意我們?nèi)绾蝹鬟f props 到基礎(chǔ)構(gòu)造函數(shù)的:
constructor (props) {
super(props)
this.state = { date: new Date() }
}
類組件應(yīng)始終使用 props 調(diào)用基礎(chǔ)構(gòu)造函數(shù)。 接下來,我們將使 Clock 設(shè)置自己的計時器并每秒更新一次。
在具有許多組件的應(yīng)用程序中,在銷毀時釋放組件所占用的資源非常重要。
每當(dāng) Clock 組件第一次加載到 DOM 中的時候,我們都想生成定時器,這在 Taro/React 中被稱為掛載。
同樣,每當(dāng) Clock 生成的這個 DOM 被移除的時候,我們也會想要清除定時器,這在 Taro/React 中被稱為卸載。
我們可以在組件類上聲明特殊的方法,當(dāng)組件掛載或卸載時,來運行一些代碼:
class Clock extends Component {
constructor (props) {
super(props)
this.state = { date: new Date() }
}
componentDidMount() {
}
componentWillUnmount() {
}
render () {
return (
<View>
<Text>Hello, world!</Text>
<Text>現(xiàn)在的時間是 {this.state.date.toLocaleTimeString()}.</Text>
</View>
)
}
}
這些方法被稱作生命周期鉤子。
當(dāng)組件輸出到 DOM 后會執(zhí)行 componentDidMount() 鉤子,這是一個建立定時器的好地方:
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
)
}
注意我們?nèi)绾卧?this 中保存定時器 ID。
雖然 this.props 由 Taro 本身設(shè)置以及 this.state 具有特殊的含義,但如果需要存儲不用于視覺輸出的東西,則可以手動向類中添加其他字段。
如果你不在 render() 中使用某些東西,它就不應(yīng)該在狀態(tài)中。
我們將在 componentWillUnmount() 生命周期鉤子中卸載計時器:
componentWillUnmount () {
clearInterval(this.timerID)
}
最后,我們實現(xiàn)了每秒鐘執(zhí)行的 tick() 方法。
它將使用 this.setState() 來更新組件局部狀態(tài):
import Taro, { Component } from '@tarojs/taro'
class Clock extends Component {
constructor (props) {
super(props)
this.state = { date: new Date() }
}
componentDidMount () {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount () {
clearInterval(this.timerID)
}
tick () {
this.setState({
date: new Date()
});
}
render() {
return (
<View>
<Text>Hello, world!</Text>
<Text>現(xiàn)在的時間是 {this.state.date.toLocaleTimeString()}.</Text>
</View>
)
}
}
關(guān)于 setState() 這里有三件事情需要知道:
例如,此代碼不會重新渲染組件:
// Wrong
this.state.comment = 'Hello'
應(yīng)當(dāng)使用 setState():
// Correct
this.setState({ comment: 'Hello' })
setState() 函數(shù)是唯一能夠更新 this.state 的地方。
Taro 可以將多個 setState() 調(diào)用合并成一個調(diào)用來提高性能。
因為 this.state 和 props 一定是異步更新的,所以你不能在 setState 馬上拿到 state 的值,例如:
// 假設(shè)我們之前設(shè)置了 this.state.counter = 0
updateCounter () {
this.setState({
counter: 1
})
console.log(this.state.counter) // 這里 counter 還是 0
}
正確的做法是這樣,在 setState 的第二個參數(shù)傳入一個 callback:
// 假設(shè)我們之前設(shè)置了 this.state.counter = 0
updateCounter () {
this.setState({
counter: 1
}, () => {
// 在這個函數(shù)內(nèi)你可以拿到 setState 之后的值
})
}
這是 Taro 和 React 另一個不同的地方:React 的 setState 不一定總是異步的,他內(nèi)部有一套事務(wù)機制控制,且 React 15/16 的實現(xiàn)也各不相同。而對于 Taro 而言,setState 之后,你提供的對象會被加入一個數(shù)組,然后在執(zhí)行下一個 eventloop 的時候合并它們。
當(dāng)你調(diào)用 setState(),Taro 將合并你提供的對象到當(dāng)前的狀態(tài)中。
例如,你的狀態(tài)可能包含幾個獨立的變量:
constructor(props) {
super(props)
this.state = {
posts: [],
comments: []
}
}
然后通過調(diào)用獨立的 setState() 調(diào)用分別更新它們:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
})
})
}
合并是淺合并,所以 this.setState({comments}) 不會改變 this.state.posts 的值,但會完全替換 this.state.comments 的值。
更多建議: