React常用Hooks
原文合集地址如下,有需要的朋友可以關注
本文地址
合集地址
React 提供了許多常用的 Hooks,用于在函數(shù)組件中添加狀態(tài)管理、副作用處理和其他功能,下面介紹其中幾個常用的,React還有很多其他hooks。
useState:
useSate用于在函數(shù)組件中添加狀態(tài)管理。它返回一個狀態(tài)值和更新該狀態(tài)值的函數(shù)。 使用時一些特點和注意事項
正確定義初始狀態(tài):在使用
useState
時,需要為初始狀態(tài)提供一個合適的值。確保初始狀態(tài)的類型與后續(xù)狀態(tài)的類型保持一致,避免出現(xiàn)類型錯誤。解構(gòu)數(shù)組:
useState
返回一個包含狀態(tài)值和更新狀態(tài)值的函數(shù)的數(shù)組,通??梢允褂脭?shù)組解構(gòu)來獲取它們。例如:const [state, setState] = useState(initialState);
。這樣做可以提高代碼的可讀性。更新狀態(tài):使用
setState
函數(shù)來更新狀態(tài)值。注意,setState
并不會像類組件中的setState
方法一樣自動合并更新,而是替換整個狀態(tài)對象。因此,在更新狀態(tài)時,請確保包含了所有需要保留的狀態(tài)值,而不僅僅是更新的部分。異步更新:由于狀態(tài)更新是異步的,多次連續(xù)調(diào)用
setState
不會立即反映到狀態(tài)值上。如果需要基于先前的狀態(tài)進行更新,可以使用回調(diào)函數(shù)的形式調(diào)用setState
。例如:setState(prevState => prevState + 1);
。函數(shù)式更新:當新的狀態(tài)值依賴于先前的狀態(tài)值時,可以使用函數(shù)式更新形式。這樣可以避免依賴于當前狀態(tài)的值,并確保獲取到最新的狀態(tài)。例如:
setState(prevState => prevState + 1);
。
import?{?Button?}?from?'antd';
import?React,?{?useState?}?from?'react';
const?Test?=?(props:?any)?=>?{
????const?[count,?setCount]?=?useState(0);
????const?onChange?=?()?=>?{
????????setCount(count?+?1);
????????//?異步更新有時候會不生效,需要這樣寫
????????setCount(pre?=>?pre?+?1);
????}
????return?(
????????<div>
????????????{count}
????????????<Button?onClick={onChange}>點擊</Button>
????????</div>
????)
}
export?default?Test;
useEffect
用于處理副作用,例如數(shù)據(jù)獲取、訂閱、事件處理等。它在組件渲染完成后執(zhí)行,并可以在組件更新時重新執(zhí)行。useEffect
是 React 中常用的 Hook 之一,用于處理副作用操作,例如數(shù)據(jù)獲取、訂閱、事件監(jiān)聽等。useEffect
在組件渲染后執(zhí)行,并可以在組件更新時重新執(zhí)行。
useEffect
接受兩個參數(shù):一個副作用函數(shù)和一個依賴項數(shù)組。
副作用函數(shù)是在組件渲染后執(zhí)行的函數(shù)。它可以包含任何副作用操作,例如訂閱事件、發(fā)送網(wǎng)絡請求、操作 DOM 等。該函數(shù)可以返回一個清理函數(shù),用于在組件卸載或重新渲染之前執(zhí)行清理操作。
依賴項數(shù)組是一個可選的參數(shù),用于指定副作用函數(shù)依賴的值。當依賴項數(shù)組發(fā)生變化時,useEffect
將重新執(zhí)行副作用函數(shù)。如果不提供依賴項數(shù)組,副作用函數(shù)將在每次組件更新時都執(zhí)行。如果傳入一個空數(shù)組 []
,副作用函數(shù)將只在組件首次渲染后執(zhí)行,不會重新執(zhí)行。
以下是 useEffect
的基本用法:
import?{?useEffect?}?from?'react';
function?MyComponent()?{
//?無依賴項,會一值執(zhí)行
?useEffect(()?=>?{
??//?操作
???
??});
//?依賴項為空,組件初始化會執(zhí)行一次
useEffect(()?=>?{
??//?操作
???
??},[]);
??//?依賴于某個變量或函數(shù),在依賴項發(fā)生變化后觸發(fā)
??useEffect(()?=>?{
????//?在組件渲染后執(zhí)行副作用操作
????//?返回一個清理函數(shù)(可選)
????return?()?=>?{
?????//?在組件卸載或重新渲染之前執(zhí)行清理操作
????//該清理函數(shù)將在組件卸載或重新渲染之前執(zhí)行
????};
??},?[/*?依賴項數(shù)組?*/]);
??return?(
???<div></div>
??);
}
下面是一些關于 useEffect
的常見用法和注意事項:
數(shù)據(jù)獲取和訂閱:可以在
useEffect
中進行異步操作,例如發(fā)起網(wǎng)絡請求獲取數(shù)據(jù)或訂閱事件。確保在清理函數(shù)中取消訂閱或中斷請求,以避免內(nèi)存泄漏。依賴項數(shù)組的使用:通過依賴項數(shù)組,可以控制副作用函數(shù)的執(zhí)行時機。只有當依賴項發(fā)生變化時,才會重新執(zhí)行副作用函數(shù)。如果不提供依賴項數(shù)組,則副作用函數(shù)將在每次組件更新時都執(zhí)行。
空依賴項數(shù)組的使用:如果副作用函數(shù)不依賴任何狀態(tài)或?qū)傩?,可以傳入一個空數(shù)組
[]
,使副作用函數(shù)僅在組件首次渲染后執(zhí)行一次。清理函數(shù)的使用:如果副作用函數(shù)需要進行清理操作,例如取消訂閱或清除定時器,請在副作用函數(shù)中返回一個清理函數(shù)。該清理函數(shù)將在組件卸載或重新渲染之前執(zhí)行。
異步操作和更新狀態(tài):在副作用函數(shù)中進行異步操作時,確保正確處理狀態(tài)的更新。使用函數(shù)式更新或通過依賴項數(shù)組傳入更新的狀態(tài)。
useContext
當使用 useContext
Hook 時,可以方便地在 React 組件中訪問全局的上下文數(shù)據(jù)。下面是一個使用 useContext
的簡單例子:
首先,創(chuàng)建一個上下文對象:
import?React,?{?createContext?}?from?'react';
//?創(chuàng)建上下文對象
const?MyContext?=?createContext();
//?上下文提供器
function?MyContextProvider({?children?})?{
??const?sharedData?=?'Shared?Data';
??return?(
????<MyContext.Provider?value={sharedData}>
??????{children}
????</MyContext.Provider>
??);
}
在上面的例子中,創(chuàng)建了一個名為 MyContext
的上下文對象,并通過 MyContext.Provider
提供器將共享數(shù)據(jù) sharedData
傳遞給子組件。
然后,在需要訪問上下文數(shù)據(jù)的組件中使用 useContext
:
import?React,?{?useContext?}?from?'react';
function?MyComponent()?{
??const?sharedData?=?useContext(MyContext);
??return?(
????<div>
??????Shared?Data:?{sharedData}
????</div>
??);
}
使用 useContext
Hook 來獲取 MyContext
上下文的值,并將其賦值給 sharedData
變量。然后,可以在組件中使用該值進行渲染或其他操作。
注意事項:
使用
useContext
前,確保已在組件樹中的某個地方提供了上下文。在上面的例子中,通過MyContext.Provider
提供器在組件樹中提供了上下文數(shù)據(jù)。上下文數(shù)據(jù)的更新:當上下文數(shù)據(jù)發(fā)生變化時,使用
useContext
的組件會自動重新渲染。這意味著,當共享數(shù)據(jù)發(fā)生更改時,使用該上下文的所有組件都會更新。上下文嵌套:React 允許上下文進行嵌套。在嵌套的情況下,使用
useContext
會獲取最接近的上層提供器的值。上下文的性能優(yōu)化:當上下文數(shù)據(jù)較大或頻繁變化時,可以使用
React.memo
、useMemo
或自定義的優(yōu)化方法來優(yōu)化上下文的性能。避免過度使用上下文:上下文是用于共享數(shù)據(jù)的有用工具,但過度使用可能導致組件之間的耦合性增加。請在需要共享數(shù)據(jù)的組件之間仔細考慮使用上下文的合適程度。
使用 useContext
可以方便地訪問和共享上下文數(shù)據(jù),但請確保在使用前提供了上下文,并注意上述的注意事項,以確保正確使用上下文功能。
useReducer
useReducer
是 React 中的一個常用 Hook,用于管理具有復雜狀態(tài)邏輯的組件。它類似于 Redux 中的 reducer,接收一個狀態(tài)和操作函數(shù),并返回新的狀態(tài)和派發(fā)操作的函數(shù)。
使用 useReducer
時,需要定義一個 reducer 函數(shù)和初始狀態(tài)。
reducer 函數(shù)接收當前狀態(tài)和一個操作(action),并根據(jù)操作的類型來更新狀態(tài)。它返回更新后的狀態(tài)。reducer 函數(shù)的定義類似于 Redux 中的 reducer:
function?reducer(state,?action)?{
??switch?(action.type)?{
????case?'INCREMENT':
??????return?{?count:?state.count?+?1?};
????case?'DECREMENT':
??????return?{?count:?state.count?-?1?};
????default:
??????return?state;
??}
}
初始狀態(tài)是狀態(tài)的初始值:
const?initialState?=?{?count:?0?};
然后,使用 useReducer
Hook 在組件中應用 reducer:
import?React,?{?useReducer?}?from?'react';
function?Counter()?{
??const?[state,?dispatch]?=?useReducer(reducer,?initialState);
??return?(
????<div>
??????Count:?{state.count}
??????<button?onClick={()?=>?dispatch({?type:?'INCREMENT'?})}>Increment</button>
??????<button?onClick={()?=>?dispatch({?type:?'DECREMENT'?})}>Decrement</button>
????</div>
??);
}
在上述例子中,我們使用 useReducer
定義了狀態(tài) state
和派發(fā)操作的函數(shù) dispatch
。我們可以根據(jù)操作的類型通過調(diào)用 dispatch
函數(shù)來派發(fā)操作,并由 reducer 函數(shù)來更新狀態(tài)。
useReducer
在處理具有復雜狀態(tài)邏輯的組件時非常有用。以下是一些使用場景:
計數(shù)器:可以使用
useReducer
來管理計數(shù)器的狀態(tài)和操作,例如增加、減少計數(shù)等。表單處理:使用
useReducer
可以更好地管理表單的狀態(tài)和用戶輸入的操作,以及進行表單驗證等復雜邏輯。數(shù)據(jù)列表:當處理復雜的數(shù)據(jù)列表時,使用
useReducer
可以更好地管理數(shù)據(jù)的加載、篩選、排序等操作,以及處理分頁等功能。
總的來說,useReducer
適用于需要管理復雜狀態(tài)邏輯的組件,并且可以幫助組織和更新狀態(tài),以及處理相關的操作。它可以代替使用 useState
的方式,特別適合管理具有多個操作類型和相關狀態(tài)的組件。
useMemo
useMemo
是 React 中的一個常用 Hook,用于在組件渲染過程中進行性能優(yōu)化,避免不必要的計算和重復渲染。
useMemo
接受兩個參數(shù):一個計算函數(shù)和依賴項數(shù)組。它會在組件渲染過程中執(zhí)行計算函數(shù),并將計算結(jié)果緩存起來。只有當依賴項數(shù)組中的值發(fā)生變化時,才會重新執(zhí)行計算函數(shù)。
使用 useMemo
可以避免在每次渲染時重復計算耗時的操作,并且可以根據(jù)依賴項的變化來更新計算結(jié)果。以下是一些 useMemo
的常見使用場景:
計算結(jié)果的緩存:當需要根據(jù)某些輸入計算結(jié)果時,可以使用
useMemo
緩存計算結(jié)果,避免重復計算。這在計算量較大的場景下特別有用。避免不必要的重渲染:當一個組件依賴于某個狀態(tài)或?qū)傩?,但這些狀態(tài)或?qū)傩缘淖兓⒉粫绊懙浇M件的渲染結(jié)果時,可以使用
useMemo
來緩存渲染結(jié)果,避免不必要的重渲染。優(yōu)化子組件的渲染:當將一個計算結(jié)果作為屬性傳遞給子組件時,可以使用
useMemo
緩存計算結(jié)果,以避免在每次父組件渲染時都重新計算并傳遞給子組件。性能敏感的比較操作:當需要進行一些性能敏感的比較操作,例如深度比較對象或數(shù)組時,可以使用
useMemo
緩存比較結(jié)果,以避免在每次渲染時重新執(zhí)行比較操作。 下面是一個使用useMemo
的簡單例子,展示如何緩存計算結(jié)果以提高性能:
import?React,?{?useMemo,?useState?}?from?'react';
function?ExpensiveComponent()?{
??//?假設這里有一個計算耗時的函數(shù)
??function?calculateExpensiveValue()?{
????//?...?復雜的計算邏輯?...
????console.log('Calculating?expensive?value...');
????return?Math.random();
??}
??//?使用?useMemo?緩存計算結(jié)果
??const?expensiveValue?=?useMemo(()?=>?calculateExpensiveValue(),?[]);
??return?(
????<div>
??????Expensive?Value:?{expensiveValue}
????</div>
??);
}
function?App()?{
??const?[count,?setCount]?=?useState(0);
??return?(
????<div>
??????<button?onClick={()?=>?setCount(count?+?1)}>Increment</button>
??????<ExpensiveComponent?/>
????</div>
??);
}
在上述代碼中,有一個 ExpensiveComponent
組件,其中包含一個計算耗時的函數(shù) calculateExpensiveValue
。為了避免在每次渲染時都重新計算 expensiveValue
,使用 useMemo
緩存計算結(jié)果。
通過將 calculateExpensiveValue
函數(shù)作為 useMemo
的第一個參數(shù),并將空數(shù)組作為依賴項傳遞給 useMemo
,確保只在組件首次渲染時執(zhí)行一次計算,并將結(jié)果緩存起來。當 count
發(fā)生變化時,ExpensiveComponent
重新渲染,但不會觸發(fā)計算函數(shù)的重新執(zhí)行。
useLayoutEffect
useLayoutEffect
是 React 中的一個 Hook,與 useEffect
類似,但它在 DOM 變更之后同步執(zhí)行,而不是在瀏覽器繪制之后執(zhí)行。它會在瀏覽器布局和繪制之前同步執(zhí)行回調(diào)函數(shù)。
使用 useLayoutEffect
可以在瀏覽器布局完成后立即執(zhí)行一些操作,以確保獲取到最新的 DOM 布局信息,并在下一次渲染之前同步地更新 UI。這在需要準確地測量 DOM 元素的尺寸、位置或進行 DOM 操作時非常有用。
下面是一個使用 useLayoutEffect
的簡單例子:
import?React,?{?useRef,?useLayoutEffect?}?from?'react';
function?MeasureElement()?{
??const?ref?=?useRef();
??useLayoutEffect(()?=>?{
????//?在瀏覽器布局完成后立即執(zhí)行操作
????const?element?=?ref.current;
????const?{?width,?height?}?=?element.getBoundingClientRect();
????//?使用測量結(jié)果進行操作
????console.log('Element?size:',?width,?height);
??},?[]);
??return?<div?ref={ref}>Measure?me!</div>;
}
function?App()?{
??return?(
????<div>
??????<MeasureElement?/>
????</div>
??);
}
在上述例子中,創(chuàng)建了一個名為 MeasureElement
的組件,在組件內(nèi)部使用了 useLayoutEffect
。在 useLayoutEffect
的回調(diào)函數(shù)中,我們可以獲取到被測量元素的最新布局信息,并進行相應的操作。
在這個例子中,我們使用 getBoundingClientRect
方法獲取被測量元素的寬度和高度,并將結(jié)果打印到控制臺。這個操作在瀏覽器布局完成后同步執(zhí)行,確保我們獲取到的尺寸是最新的。
需要注意的是,由于 useLayoutEffect
在瀏覽器布局之后同步執(zhí)行,因此它的執(zhí)行會阻塞瀏覽器的渲染過程。因此,只有在需要同步更新 UI 或測量 DOM 元素時才使用 useLayoutEffect
,避免造成性能問題。