React18 (六) hook鉤子函數

React中的鉤子函數的功能非常的強大,而它的使用又十分簡單。關於鉤子函數的使用,我們只需記住兩點:

1. 鉤子只能在React組件和自定義鉤子中使用
2. 鉤子不能在嵌套函數或其他語句(ifswitch、white、for等)中使用

React中自帶的鉤子函數

useState
useEffect
useContext
useReducer
useCallback
useRef
useMemo
useImperativeHandle
useLayoutEffect
useDebugValue(18.0新增)
useDeferredValue(18.0新增)
useTransition(18.0新增)
useId(18.0新增)
useSyncExternalStore(18.0新增)
useInsertionEffect(18.0新增)

UseMemo

useMemo和useCallback十分相似,useCallback用來緩存函數對象,useMemo用來緩存函數的執行結果。在組件中,會有一些函數具有十分的複雜的邏輯,執行速度比較慢。閉了避免這些執行速度慢的函數返回執行,可以通過useMemo來緩存它們的執行結果,像是這樣:

const result = useMemo(()=>{
    return 複雜邏輯函數();
},[依賴項])

useMemo中的函數會在依賴項發生變化時執行,注意!是執行,這點和useCallback不同,useCallback是創建。執行後返回執行結果,如果依賴項不發生變化,則一直會返回上次的結果,不會再執行函數。這樣一來就避免複雜邏輯的重複執行。

UseImperativeHandle

在React中可以通過forwardRef來指定要暴露給外部組件的ref:

const TestButton = forwardRef((props, ref) => {
    return <button ref={ref}>Test</button>
});

上例中,TestButton組件將button的ref作爲組件的ref向外部暴露,其他組件在使用TestButton時,就可以通過ref屬性訪問:

<TestButton ref={btnRef}/>

通過useImperativeHandle可以手動的指定ref要暴露的對象,比如可以修改TestButton組件如下:

const TestButton = forwardRef((props, ref) => {

    useImperativeHandle(ref,()=> {
        return {
            name:'test-button'
        };
    });

    return <button>test</button>
});

useImperativeHandle的第二個參數是一個函數,函數的返回值會自動賦值給ref(current屬性)。上例中,我們將返回值爲{name:'test-button'}。實際開發中,我們可以將一些操作方法定義到對象中,這樣可以有效的減少組件對DOM對象的直接操作。

const TestButton = forwardRef((props, ref) => {

    const btnRef = useRef();

    useImperativeHandle(ref,()=> {
        return {
            setDisabled(){
                btnRef.current.disabled = true;
            }
        };
    });

    return <button ref={btnRef}>Disable</button>
});

const App = () => {
    
    const btnRef = useRef();

    const clickHandler = () => {
        btnRef.current.setDisabled();
    };

    return <div>
        <TestButton ref={btnRef}/>
        <button onClick={clickHandler}>ok</button>
    </div>;
};

UseLayoutEffect

useLayoutEffect的方法簽名和useEffect一樣,功能也類似。不同點在於,useLayoutEffect的執行時機要早於useEffect,它會在DOM改變後調用。在老版本的React中它和useEffect的區別比較好演示,React18中,useEffect的運行方式有所變化,所以二者區別不好演示。useLayoutEffect使用場景不多,實際開發中,在effect中需要修改元素樣式,且使用useEffect會出現閃爍現象時可以使用useLayoutEffect進行替換。

UseDebugValue

用來給自定義鉤子設置標籤,標籤會在React開發工具中顯示,用來調試自定義鉤子,不常用。

UseDeferredValue

useDeferredValue用來設置一個延遲的state,比如我們創建一個state,並使用useDeferredValue獲取延遲值:

const [queryMember, setQueryMember] = useState('');
const deferredQueryMember = useDeferredValue(queryMember);

上邊的代碼中queryMember就是一個常規的state,deferredQueryMember就是queryMember的延遲值。設置延遲值後每次調用setState後都會觸發兩次組件的重新渲染。第一次時,deferredQueryMember的值是queryMember修改前的值,第二次纔是修改後的值。換句話,延遲值相較於state來說總會慢一步更新。延遲值可以用在這樣一個場景,一個state需要在多個組件中使用。一個組件的渲染比較快,而另一個組件的渲染比較慢。這樣我們可以爲該state創建一個延遲值,渲染快的組件使用正常的state優先顯示。渲染慢的組件使用延遲值,慢一步渲染。當然必須結合React.memo或useMemo才能真正的發揮出它的作用。

UseTransition

當我們在組件中修改state時,會遇到複雜一些的state,當修改這些state時,甚至會阻塞到整個應用的運行,爲了降低這種state的影響,React爲我們提供了useTransition,通過useTransition可以降低setState的優先級。useTransition會返回一個數組,數組中有兩個元素,第一個元素是isPending,它是一個變量用來記錄transition是否在執行中。第二個元素是startTransition,它是一個函數,可以將setState在其回調函數中調用,這樣setState方法會被標記爲transition並不會立即執行,而是在其他優先級更高的方法執行完畢,纔會執行。除了useTransition外,React還直接爲爲我們提供了一個startTransition函數,在不需要使用isPending時,可以直接使用startTransition也可以達到相同的效果。

UseId

生成唯一id,使用於需要唯一id的場景,但不適用於列表的key。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章