若是你以前對於Hooks
沒有了解,那麼你可能須要看下概述部分。你或許也能夠在一些常見的問題中找到有用的信息。html
const [state, setState] = useState(initialState);
複製代碼
返回有狀態值,以及更新這個狀態值的函數。github
在初始渲染的時候,返回的狀態(state
)與做爲第一個參數(initialState
)傳遞的值相同。api
setState
函數用於更新state
。setState
接受一個新的狀態值,並將組件的從新渲染排入隊列。數組
setState(newState);
複製代碼
在後續從新渲染期間,useState
返回的第一個值將始終是應用更新後的最新狀態。瀏覽器
若是更新狀態須要用到前面的狀態,那能夠傳遞一個函數給setXxxx
,相似於類組件中的setState
。這個函數能夠接收先前的值,而後返回更新以後的值。函數
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<> Count: {count} <button onClick={() : setCount(0)}>Reset</button> <button onClick={() : setCount(prevCount : prevCount + 1)}>+</button> <button onClick={() : setCount(prevCount : prevCount - 1)}>-</button> </> ); } 複製代碼
就像這樣,給setCount
傳遞一個函數,這個函數接收一個參數(上一個狀態值),最後返回新的狀態值用以setCount
。佈局
注意: 與類組件中的
setState
方法不一樣,useState
不會自動合併更新對象。 可是你能夠本身作到這點:性能setXxxx(prevState : { // Object.assign would also work return {...prevState, ...updatedValues}; }); 複製代碼
另外一個選項是使用
useReducer
,它更適合管理包含多個子值的狀態對象。
initialState
參數是初始渲染期間使用的狀態。在隨後的渲染中,它被忽略了。若是初始狀態是複雜計算的結果,則能夠改成提供函數,該函數僅在初始渲染時執行:
const [state, setState] = useState(() : {
const initialState = someExpensiveComputation(props);
return initialState;
});
複製代碼
useEffect(didUpdate);
複製代碼
接受包含命令式,可能有反作用代碼的函數。
函數組件的主體內部不容許發生改變,訂閱,計時器,日誌記錄和其餘反作用(稱爲React
的渲染階段)。這樣作會致使UI
中的錯誤和不一致性混亂。
相反,使用useEffect
。傳遞給useEffect
的函數將在渲染結束後運行。將效果(反作用)視爲從React
的純函數進入命令式的逃脫艙。
默認狀況下,效果在每次完成渲染後運行,可是你能夠選擇僅在某些值發生更改時觸發它。前面介紹effect hook時有提到,本文下面仍然會詳細介紹。
一般,效果會建立一些在組件卸載時須要清理的資源,例如訂閱或計時器ID。爲此,傳遞給useEffect
的函數可能會返回一個清理函數。例如,要建立訂閱:
useEffect(() : {
const subscription = props.source.subscribe();
return () : {
// Clean up the subscription
subscription.unsubscribe();
};
});
複製代碼
返回的清除函數在從UI中卸載組件以前運行,以防止內存泄漏。此外,若是組件呈現屢次(一般如此),則在執行下一個效果以前會清除先前的效果。 在咱們的示例中,這意味着每次更新都會建立一個新訂閱。要避免在每次更新時觸發效果,請繼續往下看。
與componentDidMount
和componentDidUpdate
不一樣,傳遞給useEffect
的函數在延遲事件期間在佈局和繪製後觸發。這使得它適用於許多常見的反作用,例如設置訂閱和事件處理程序,由於大多數類型的工做不該阻止瀏覽器更新屏幕。
可是,並不是全部效果均可以推遲。例如,用戶可見的DOM改變必須在下一次繪製以前同步觸發,以便用戶不會感受到視覺上的不一致。對於這些類型的效果,React
提供了兩個額外的Hook:useMutationEffect和useLayoutEffect。這些Hook
與useEffect
具備相同的api
,而且僅在觸發時有所不一樣。
雖然useEffect
會延遲到瀏覽器繪製完成以後,但它保證在任何新渲染以前觸發,也就是說在開始新的更新以前,React
將始終刷新先前渲染的效果。
效果的默認行爲是在每次完成渲染後觸發效果。這樣,若是其中一個輸入發生變化,則始終會從新建立效果。
可是,在某些狀況下,這多是不須要的,例如上一節中的訂閱示例。僅當source prop
已更改時,咱們無需在每次更新時建立新訂閱。
要實現此功能,請將第二個參數傳遞給useEffect
,它是效果所依賴的值數組。咱們更新的示例如今看起來像這樣:
useEffect(
() : {
const subscription = props.source.subscribe();
return () : {
subscription.unsubscribe();
};
},
[props.source],
);
複製代碼
如今只有在 props.source
更改時纔會從新建立訂閱。傳入一個空數組[]輸入告訴React
你的效果不依賴於組件中的任何值,所以該效果僅在mount
和unmount
上運行,從不在更新時運行。
注意 輸入數組不做爲參數傳遞給效果函數。 但從概念上講,這就是它們所表明的內容:效果函數中引用的每一個值也應出如今輸入數組中,這樣纔有意義。而且從以前能夠得知,只要數組裏的內容有一個不一樣,那就會再次調用這個效果。
const context = useContext(Context);
複製代碼
接受上下文對象(從React.createContext
返回的值)並返回當前上下文值,由給定上下文的最近上下文提供程序給出。
當提供程序更新時,此Hook
將使用最新的上下文值觸發從新呈現。
如下鉤子能夠是上一節中基本鉤子的變體,也能夠僅用於特定邊緣狀況。不強調預先學習它們。
const [state, dispatch] = useReducer(reducer, initialState);
複製代碼
useState的替代方案。接受類型爲(state,action) : newState
的reducer
,並返回與dispatch
方法配對的當前狀態。 (若是熟悉Redux
,你已經知道它是如何工做的。)
這是useState
部分的計數器示例,用reducer
重寫:
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'reset':
return initialState;
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<> Count: {state.count} <button onClick={() : dispatch({type: 'reset'})}> Reset </button> <button onClick={() : dispatch({type: 'increment'})}>+</button> <button onClick={() : dispatch({type: 'decrement'})}>-</button> </> ); } 複製代碼
useReducer
接受可選的第三個參數initialAction
。若是提供,則在初始渲染期間應用初始操做。這對於計算包含經過props傳遞的值的初始狀態很是有用:
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'reset':
return {count: action.payload};
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(
reducer,
initialState,
{type: 'reset', payload: initialCount},
);
return (
<> Count: {state.count} <button onClick={() : dispatch({type: 'reset', payload: initialCount})}> Reset </button> <button onClick={() : dispatch({type: 'increment'})}>+</button> <button onClick={() : dispatch({type: 'decrement'})}>-</button> </> ); } 複製代碼
當你具備涉及多個子值的複雜狀態邏輯時,useReducer
一般優於useState
。它還容許你優化觸發深度更新的組件的性能,由於你能夠傳遞調度而不是回調。
const memoizedCallback = useCallback(
() : {
doSomething(a, b);
},
[a, b],
);
複製代碼
返回一個memoized回調。
傳遞內聯回調和一組輸入。 useCallback
將返回一個回憶的memoized
版本,該版本僅在其中一個輸入發生更改時纔會更改。當將回調傳遞給依賴於引用相等性的優化子組件以防止沒必要要的渲染(例如,shouldComponentUpdate
)時,這很是有用。
useCallback(fn,inputs) 等效 useMemo(() : fn,inputs)。
注意 輸入數組不做爲參數傳遞給回調。但從概念上講,這就是它們所表明的內容:回調中引用的每一個值也應出如今輸入數組中。未來,一個足夠先進的編譯器能夠自動建立這個數組。相似於上面提到的
effect
第二個參數。
const memoizedValue = useMemo(() : computeExpensiveValue(a, b), [a, b]);
複製代碼
返回一個memoized
值。
傳遞「建立」功能和輸入數組。 useMemo
只會在其中一個輸入發生更改時從新計算memoized
值。此優化有助於避免在每一個渲染上進行昂貴的計算。
若是未提供數組,則只要將新函數實例做爲第一個參數傳遞,就會計算新值。 (使用內聯函數,在每一個渲染上。)
注意: 輸入數組不做爲參數傳遞給函數。但從概念上講,這就是它們所表明的內容:函數內部引用的每一個值也應出如今輸入數組中。
const refContainer = useRef(initialValue);
複製代碼
useRef
返回一個可變的ref
對象,其.current
屬性被初始化爲傳遞的參數(initialValue
)。返回的對象將持續整個組件的生命週期。
一個常見的用例是強制訪問child
:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () : {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
複製代碼
請注意,useRef
比ref
屬性更有用。保持任何可變值的方式相似於在類中使用實例字段的方法。
useImperativeMethods(ref, createInstance, [inputs])
複製代碼
useImperativeMethods
自定義使用ref
時公開給父組件的實例值。與往常同樣,在大多數狀況下應避免使用refs
的命令式代碼。 useImperativeMethods
應與forwardRef
一塊兒使用:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeMethods(ref, () : ({
focus: () : {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />; } FancyInput = forwardRef(FancyInput); 複製代碼
在此示例中,呈現<FancyInput ref = {fancyInputRef} />
的父組件將可以調用fancyInputRef.current.focus()
。
api
與useEffect
相同,但在更新兄弟組件以前,它在React
執行其DOM改變的同一階段同步觸發。使用它來執行自定義DOM改變。
在可能的狀況下首選標準useEffect
以阻止可見的更新。
注意 避免在
useMutationEffect
中讀取DOM。在讀取計算樣式或佈局信息時,useLayoutEffect
更合適。
api
與useEffect
相同,但在全部DOM改變後同步觸發。使用它來從DOM讀取佈局並同步從新渲染。在瀏覽器有機會繪製以前,將在useLayoutEffect
內部計劃的更新將同步刷新。
在可能的狀況下首選標準useEffect
以阻止視覺更新。
提示 若是你正在從類組件遷移代碼,則
useLayoutEffect
會在與componentDidMount
和componentDidUpdate
相同的階段觸發,所以若是你不肯定Hook
要使用哪一種效果,則他可能風險最小。