以前吆豹,React API 只有一套钠糊,現(xiàn)在有兩套:類(class)API 和基于函數(shù)的鉤子(hooks) API锡凝。
官方[推薦]使用鉤子(函數(shù))粘昨,而不是類。因?yàn)殂^子更簡(jiǎn)潔,代碼量少张肾,用起來(lái)比較"輕"芭析,而類比較"重"。而且吞瞪,鉤子是函數(shù)馁启,更符合 React 函數(shù)式的本質(zhì)。
類(class)是數(shù)據(jù)和邏輯的封裝芍秆。 也就是說(shuō)惯疙,組件的狀態(tài)和操作方法是封裝在一起的。如果選擇了類的寫法妖啥,就應(yīng)該把相關(guān)的數(shù)據(jù)和操作霉颠,都寫在同一個(gè) class 里面。
函數(shù)一般來(lái)說(shuō)荆虱,只應(yīng)該做一件事蒿偎,就是返回一個(gè)值。 如果你有多個(gè)操作怀读,每個(gè)操作應(yīng)該寫成一個(gè)單獨(dú)的函數(shù)诉位。而且,數(shù)據(jù)的狀態(tài)應(yīng)該與操作方法分離菜枷。根據(jù)這種理念苍糠,React 的函數(shù)組件只應(yīng)該做一件事情:返回組件的 HTML 代碼,而沒(méi)有其他的功能啤誊。因?yàn)檫€有許多狀態(tài)和變量要保存岳瞭,這個(gè)時(shí)候就有了鉤子。
鉤子(hook)的作用
鉤子(hook)就是 React 函數(shù)組件的副效應(yīng)解決方案坷衍,用來(lái)為函數(shù)組件引入副效應(yīng)寝优。 函數(shù)組件的主體只應(yīng)該用來(lái)返回組件的 HTML 代碼,所有的其他操作(副效應(yīng))都必須通過(guò)鉤子引入枫耳。
常用鉤子:
useState():保存狀態(tài)
useContext():保存上下文
useRef():保存引用
useEffect()是通用的副效應(yīng)鉤子
useEffect()的用法
import React, { useEffect } from 'react';
function Welcome(props) {
useEffect(() => {
document.title = '加載完成';
});
return <h1>Hello, {props.name}</h1>;
}
useEffect()的作用就是指定一個(gè)副效應(yīng)函數(shù),組件每渲染一次孟抗,該函數(shù)就自動(dòng)執(zhí)行一次迁杨。組件首次在網(wǎng)頁(yè) DOM 加載后,副效應(yīng)函數(shù)也會(huì)執(zhí)行凄硼。
有時(shí)候铅协,我們不希望useEffect()每次渲染都執(zhí)行,這時(shí)可以使用它的第二個(gè)參數(shù)摊沉,使用一個(gè)數(shù)組指定副效應(yīng)函數(shù)的依賴項(xiàng)狐史,只有依賴項(xiàng)發(fā)生變化,才會(huì)重新渲染。
function Welcome(props) {
useEffect(() => {
document.title = `Hello, ${props.name}`;
}, [props.name]);
return <h1>Hello, {props.name}</h1>;
}
如何獲取數(shù)據(jù)
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(() => {
const fetchData = async () => {
const result = await axios(
'https://hn.algolia.com/api/v1/search?query=redux',
);
setData(result.data);
};
fetchData();
}, []);
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}
export default App;
由于獲取數(shù)據(jù)只需要執(zhí)行一次骏全,所以上例的useEffect()的第二個(gè)參數(shù)為一個(gè)空數(shù)組苍柏。
useEffect() 的返回值
副效應(yīng)是隨著組件加載而發(fā)生的,那么組件卸載時(shí)姜贡,可能需要清理這些副效應(yīng)试吁。
useEffect()允許返回一個(gè)函數(shù),在組件卸載時(shí)楼咳,執(zhí)行該函數(shù)熄捍,清理副效應(yīng)。如果不需要清理副效應(yīng)母怜,useEffect()就不用返回任何值余耽。
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
}, [props.source]);
useEffect() 的注意點(diǎn)
使用useEffect()時(shí),有一點(diǎn)需要注意苹熏。如果有多個(gè)副效應(yīng)宾添,應(yīng)該調(diào)用多個(gè)useEffect(),而不應(yīng)該合并寫在一起柜裸。
function App() {
const [varA, setVarA] = useState(0);
const [varB, setVarB] = useState(0);
useEffect(() => {
const timeoutA = setTimeout(() => setVarA(varA + 1), 1000);
const timeoutB = setTimeout(() => setVarB(varB + 2), 2000);
return () => {
clearTimeout(timeoutA);
clearTimeout(timeoutB);
};
}, [varA, varB]);
return <span>{varA}, {varB}</span>;
}
上面的例子是錯(cuò)誤的寫法缕陕,副效應(yīng)函數(shù)里面有兩個(gè)定時(shí)器,它們之間并沒(méi)有關(guān)系疙挺,其實(shí)是兩個(gè)不相關(guān)的副效應(yīng)扛邑,不應(yīng)該寫在一起。正確的寫法是將它們分開寫成兩個(gè)useEffect()铐然。
function App() {
const [varA, setVarA] = useState(0);
const [varB, setVarB] = useState(0);
useEffect(() => {
const timeout = setTimeout(() => setVarA(varA + 1), 1000);
return () => clearTimeout(timeout);
}, [varA]);
useEffect(() => {
const timeout = setTimeout(() => setVarB(varB + 2), 2000);
return () => clearTimeout(timeout);
}, [varB]);
return <span>{varA}, {varB}</span>;
}
文章來(lái)源阮一峰老師的一篇文章
https://www.ruanyifeng.com/blog/2020/09/react-hooks-useeffect-tutorial.html