在react最新的一個(gè)大版本中曲初,正式的給我們帶來(lái)了hook:React v16.8: The One With Hooks就是讓我們不再只能使用 class 來(lái)實(shí)現(xiàn)有狀態(tài)的組件管毙。
熟悉react的朋友應(yīng)該都了解铃将,當(dāng)我們需要具有狀態(tài)的組件食店,或者需要使用生命周期函數(shù)來(lái)完成一些操作的時(shí)候霎奢,就不可避免的需要這樣:
class Component extend React.Component {
...
}
如果這個(gè)組件內(nèi)部足夠復(fù)雜那倒還行蠕蚜,但如果只是涉及簡(jiǎn)單的數(shù)據(jù)改變,而讓我們每次實(shí)現(xiàn)它都需要實(shí)現(xiàn)一個(gè)class這也是一個(gè)讓人很惱火的事情乎折,同時(shí)也增加了我們?nèi)粘i_(kāi)發(fā)的代碼量绒疗。但有了hook之后,我們就可以愉快的使用hook來(lái)實(shí)現(xiàn)由狀態(tài)的函數(shù)組件了骂澄。
在hook里面主要有以下兩個(gè)比較常用的API:
- useState
- useEffect
useState
useState所要解決的問(wèn)題就是在函數(shù)中使用狀態(tài)吓蘑。比如我們需要實(shí)現(xiàn)一個(gè)可以加減的計(jì)數(shù)器:
import { useState } from 'react'
const Counter = () => {
const [count, setCount] = useState(0)
return (
<div>
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</div>
);
};
在這里我們就是使用useState來(lái)在Counter函數(shù)內(nèi)部創(chuàng)建狀態(tài),并管理狀態(tài)坟冲。
useState 接受一個(gè)參數(shù)磨镶,也就是 state 的初始值,它的返回值是一個(gè)只有兩個(gè)元素的數(shù)組健提,其中第一個(gè)元素是 state 的值琳猫,第二個(gè)元素是用于更新 state 的函數(shù)。上面那段代碼就是使用了ES6中的解構(gòu)賦值來(lái)把兩個(gè)元素分別賦值給 count 和 setCount私痹。當(dāng)然脐嫂,count和setCount 這兩個(gè)名字并不是固定的,我們可以給這兩個(gè)元素隨意的設(shè)置名字紊遵。
useState在處理簡(jiǎn)單的數(shù)據(jù)流時(shí)相較之使用class要簡(jiǎn)明方便的多账千,下面是在結(jié)合antd的代碼可以感受一下代碼量上的差距:
class Modal extends React.Component {
state = { visible: false }
showModal = () => {
this.setState({
visible: true,
});
}
handleOk = (e) => {
console.log(e);
this.setState({
visible: false,
});
}
handleCancel = (e) => {
console.log(e);
this.setState({
visible: false,
});
}
render() {
return (
<div>
<Button type="primary" onClick={this.showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<p>this is a modal</p>
</Modal>
</div>
);
}
}
這是antd所提供的一個(gè)關(guān)于model的組件,其內(nèi)部就是通過(guò)維護(hù)visible的狀態(tài)來(lái)控制這個(gè)model是否顯示暗膜。我們可以看到匀奏,雖然只是簡(jiǎn)單的兩種狀態(tài),但我們?cè)趧?chuàng)建visible這一state的同時(shí)桦山,還需要使用三個(gè)函數(shù)去控制改變它。而當(dāng)我們使用useState后就很簡(jiǎn)單了:
const Modal = () => {
const [visible , changeVisible] = useState(false)
return (
<div>
<Button type="primary" onClick={()=>changeVisible(true)}>open</Button>
<Modal
title="Basic Modal"
visible={visible}
onOk={()=>changeVisible(false)}
onCancel={()=>changeVisible(false)}
>
<p>this is a modal</p>
</Modal>
</div>
)
}
useEffect
上面提到醋旦,在需要使用狀態(tài)和生命周期函數(shù)的時(shí)候我們需要使用class恒水,上面的useState是為我們解決狀態(tài)問(wèn)題的,而這個(gè)userEffect則是為我們解決在函數(shù)組件中生命周期的問(wèn)題的饲齐。
在 Counter 組件中钉凌,如果我們想要在用戶點(diǎn)擊“+”或者“-”按鈕之后把計(jì)數(shù)值體現(xiàn)在網(wǎng)頁(yè)標(biāo)題上,這就是一個(gè)修改 DOM 的副作用操作捂人,所以我們需要使用componentDidMount或者componentDidUpdate御雕,因此我們得把 Counter 寫(xiě)成 class 組件矢沿,但在在使用useEffect后我們可以這么寫(xiě):
import { useState, useEffect } from 'react'
const Counter = () => {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `Count: ${count}`
})
return (
<div>
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</div>
)
}
在這里userEffect就接受一個(gè)函數(shù)作為參數(shù),每次Counter組件發(fā)生渲染的時(shí)候酸纲,都會(huì)調(diào)用這個(gè)函數(shù)捣鲸,也就做到了上面所說(shuō)的那兩個(gè)生命周期函數(shù)的作用。
但需要注意的是闽坡,如果我們只傳入一個(gè)參數(shù)的話栽惶,useEffect會(huì)在每次渲染過(guò)后都調(diào)用這個(gè)函數(shù),而在我們?nèi)粘i_(kāi)發(fā)使用componentDidMount的時(shí)候疾嗅,往往可能只需要當(dāng)mount后才調(diào)用外厂,比如當(dāng)我們需要在掛載組件后去請(qǐng)求某個(gè)數(shù)據(jù),但當(dāng)update的時(shí)候則不需要去請(qǐng)求它代承。在useEffect中同樣也有方法可以實(shí)現(xiàn)這種操作汁蝶,useEffect 其實(shí)還有第二個(gè)可選參數(shù),只有當(dāng)同一 useEffect 的兩次調(diào)用的第二個(gè)參數(shù)不同時(shí)论悴,第一個(gè)參數(shù)才會(huì)被調(diào)用掖棉,所以相實(shí)現(xiàn)上面這種功能,我們只需要這樣寫(xiě):
useEffect(() => {
console.log("在這里只有第一次mount的時(shí)候才會(huì)被執(zhí)行")
}, [666]);
還有一點(diǎn)需要注意的是意荤,所有的 Hooks API 都只能在函數(shù)類型組件中使用啊片,而class 類型的組件是不能使用的。(不過(guò)也對(duì)hook本身誕生的目的就是為函數(shù)式組件服務(wù)的)