react16.7.0-alpha hooks的api介紹

若是你以前對於Hooks沒有了解,那麼你可能須要看下概述部分。你或許也能夠在一些常見的問題中找到有用的信息。html

Baisc Hooks

useState

const [state, setState] = useState(initialState);
複製代碼

返回有狀態值,以及更新這個狀態值的函數。github

在初始渲染的時候,返回的狀態(state)與做爲第一個參數(initialState)傳遞的值相同。api

setState函數用於更新statesetState接受一個新的狀態值,並將組件的從新渲染排入隊列。數組

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

useEffect(didUpdate);
複製代碼

接受包含命令式,可能有反作用代碼的函數。

函數組件的主體內部不容許發生改變,訂閱,計時器,日誌記錄和其餘反作用(稱爲React的渲染階段)。這樣作會致使UI中的錯誤和不一致性混亂。

相反,使用useEffect。傳遞給useEffect的函數將在渲染結束後運行。將效果(反作用)視爲從React的純函數進入命令式的逃脫艙。

默認狀況下,效果在每次完成渲染後運行,可是你能夠選擇僅在某些值發生更改時觸發它。前面介紹effect hook時有提到,本文下面仍然會詳細介紹。

清理effect

一般,效果會建立一些在組件卸載時須要清理的資源,例如訂閱或計時器ID。爲此,傳遞給useEffect的函數可能會返回一個清理函數。例如,要建立訂閱:

useEffect(() : {
  const subscription = props.source.subscribe();
  return () : {
    // Clean up the subscription
    subscription.unsubscribe();
  };
});
複製代碼

返回的清除函數在從UI中卸載組件以前運行,以防止內存泄漏。此外,若是組件呈現屢次(一般如此),則在執行下一個效果以前會清除先前的效果。 在咱們的示例中,這意味着每次更新都會建立一個新訂閱。要避免在每次更新時觸發效果,請繼續往下看。

effect的觸發時間

componentDidMountcomponentDidUpdate不一樣,傳遞給useEffect的函數在延遲事件期間在佈局和繪製後觸發。這使得它適用於許多常見的反作用,例如設置訂閱和事件處理程序,由於大多數類型的工做不該阻止瀏覽器更新屏幕。

可是,並不是全部效果均可以推遲。例如,用戶可見的DOM改變必須在下一次繪製以前同步觸發,以便用戶不會感受到視覺上的不一致。對於這些類型的效果,React提供了兩個額外的Hook:useMutationEffectuseLayoutEffect。這些HookuseEffect具備相同的api,而且僅在觸發時有所不一樣。

雖然useEffect會延遲到瀏覽器繪製完成以後,但它保證在任何新渲染以前觸發,也就是說在開始新的更新以前,React將始終刷新先前渲染的效果。

條件控制的effect

效果的默認行爲是在每次完成渲染後觸發效果。這樣,若是其中一個輸入發生變化,則始終會從新建立效果。

可是,在某些狀況下,這多是不須要的,例如上一節中的訂閱示例。僅當source prop已更改時,咱們無需在每次更新時建立新訂閱。

要實現此功能,請將第二個參數傳遞給useEffect,它是效果所依賴的值數組。咱們更新的示例如今看起來像這樣:

useEffect(
  () : {
    const subscription = props.source.subscribe();
    return () : {
      subscription.unsubscribe();
    };
  },
  [props.source],
);
複製代碼

如今只有在 props.source更改時纔會從新建立訂閱。傳入一個空數組[]輸入告訴React你的效果不依賴於組件中的任何值,所以該效果僅在mountunmount上運行,從不在更新時運行。

注意 輸入數組不做爲參數傳遞給效果函數。 但從概念上講,這就是它們所表明的內容:效果函數中引用的每一個值也應出如今輸入數組中,這樣纔有意義。而且從以前能夠得知,只要數組裏的內容有一個不一樣,那就會再次調用這個效果。

useContext

const context = useContext(Context);
複製代碼

接受上下文對象(從React.createContext返回的值)並返回當前上下文值,由給定上下文的最近上下文提供程序給出。

當提供程序更新時,此Hook將使用最新的上下文值觸發從新呈現。

其餘的鉤子

如下鉤子能夠是上一節中基本鉤子的變體,也能夠僅用於特定邊緣狀況。不強調預先學習它們。

useReducer

const [state, dispatch] = useReducer(reducer, initialState);
複製代碼

useState的替代方案。接受類型爲(state,action) : newStatereducer,並返回與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。它還容許你優化觸發深度更新的組件的性能,由於你能夠傳遞調度而不是回調

useCallback

const memoizedCallback = useCallback(
  () : {
    doSomething(a, b);
  },
  [a, b],
);
複製代碼

返回一個memoized回調

傳遞內聯回調和一組輸入。 useCallback將返回一個回憶的memoized版本,該版本僅在其中一個輸入發生更改時纔會更改。當將回調傳遞給依賴於引用相等性的優化子組件以防止沒必要要的渲染(例如,shouldComponentUpdate)時,這很是有用。

useCallback(fn,inputs) 等效 useMemo(() : fn,inputs)。

注意 輸入數組不做爲參數傳遞給回調。但從概念上講,這就是它們所表明的內容:回調中引用的每一個值也應出如今輸入數組中。未來,一個足夠先進的編譯器能夠自動建立這個數組。相似於上面提到的effect第二個參數。

useMemo

const memoizedValue = useMemo(() : computeExpensiveValue(a, b), [a, b]);
複製代碼

返回一個memoized值。

傳遞「建立」功能和輸入數組。 useMemo只會在其中一個輸入發生更改時從新計算memoized值。此優化有助於避免在每一個渲染上進行昂貴的計算。

若是未提供數組,則只要將新函數實例做爲第一個參數傳遞,就會計算新值。 (使用內聯函數,在每一個渲染上。)

注意: 輸入數組不做爲參數傳遞給函數。但從概念上講,這就是它們所表明的內容:函數內部引用的每一個值也應出如今輸入數組中。

useRef

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>
    </>
  );
}
複製代碼

請注意,useRefref屬性更有用。保持任何可變值的方式相似於在類中使用實例字段的方法。

useImperativeMethods

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()

useMutationEffect

apiuseEffect相同,但在更新兄弟組件以前,它在React執行其DOM改變的同一階段同步觸發。使用它來執行自定義DOM改變。

在可能的狀況下首選標準useEffect以阻止可見的更新。

注意 避免在useMutationEffect中讀取DOM。在讀取計算樣式或佈局信息時,useLayoutEffect更合適。

useLayoutEffect

apiuseEffect相同,但在全部DOM改變後同步觸發。使用它來從DOM讀取佈局並同步從新渲染。在瀏覽器有機會繪製以前,將在useLayoutEffect內部計劃的更新將同步刷新。

在可能的狀況下首選標準useEffect以阻止視覺更新。

提示 若是你正在從類組件遷移代碼,則useLayoutEffect會在與componentDidMountcomponentDidUpdate相同的階段觸發,所以若是你不肯定Hook要使用哪一種效果,則他可能風險最小。

更多地關於hooks系列請前往此處查看, 推薦一個高質量教學視頻網站, 不少免費的視頻及資源

相關文章
相關標籤/搜索