iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
0
自我挑戰組

React 30 天學習歷程系列 第 27

【Day 27】React Hook(四): 其他 React Hook 的語法

useMemo

useMmo 是用來優化性能的,他利用函式的回傳值來判斷元件是否需要重新渲染,可以用在比較複雜的邏輯處理上。它接受兩個參數,第一個是 callback,用來處理計算邏輯,第二個是 array,當 array 發生改變,useMemo 才會重新執行。useMemo 會有一個記憶值,這個記憶值就是 callback 的返回值,當 array 發生改變,才重新計算記憶值。

const memoizedValue = useMemo(callback, array)

下面是一個簡易的範例,我們在 TestComponent 中設了兩個屬性 countOnecountTwo,每次點擊 button 就會分別更新這兩個屬性,而 otherCount 應該要在 countOne 有變動時才跟著變動。但是實際運作中會發現,因為 React 的特性,只要每次 countOnecountTwo 更新,整個元件就會一起更新,所以 otherCount 也會一起更新,造成不必要的耗能。

const UserProfile = () => {
    const [countOne, setCountOne] = useState(0)
    const [countTwo, setCountTwo] = useState(0)
    const otherCount = countOne + Math.random() // 每次都跟著一起跟新
    return <div>
        <button onClick={ () => setCountOne(countOne + 1)}>+1</button>
        <button onClick={ () => setCountTwo(countTwo + 1)}>+1</button>
        { otherCount }
    </div>
}

這時候就可以使用 useMemo 來返回一個記憶值給 otherCount,這個記憶值只有在 countOne 變動時才跟著變動。

const UserProfile = () => {
    const [countOne, setCountOne] = useState(0)
    const [countTwo, setCountTwo] = useState(0)
    // const otherCount = countOne + Math.random()
    const otherCount = useMemo(() => countOne + Math.random() , [countOne]) //countOne 變動才會改變
    return <div>
        <div>{countOne}</div>
        <div>{countTwo}</div>
        <button onClick={ () => setCountOne(countOne + 1)}>+1</button>
        <button onClick={ () => setCountTwo(countTwo + 1)}>+1</button>
        { otherCount }
    </div>
}

useCallback

useCallbackuseMemo 一樣是用於性能優化,一樣是有 callbackarray 兩個參數,callback 也是處理計算邏輯,array 發生改變時,useCallback 才會執行。useCallback 的返回值也會記憶緩存起來,跟 useMemo 的差異處在於,useMemo 的返回值就是 callback 返回值,useCallback 的返回值是 callback 函式本身。

const memoizedCallback = useCallback(callback, array)

下面是一個和 useMemo 一樣的範例,但不同的是,我們用 useCallback 返回得到的函式。useCallbackuseMemo 的使用時機,取決於產品的業務邏輯。

const UserProfile = () => {
    const [countOne, setCountOne] = useState(0)
    const [countTwo, setCountTwo] = useState(0)
    const doSomeThing = (value) => {
        const obj = {
            value: value + 1
        }
        return obj
    }
    // useCallback 返回函式
    const otherCount = useCallback(() => doSomeThing(countOne) , [countOne]) //countOne 變動才會改變
    return <div>
        <div>{countOne}</div>
        <div>{countTwo}</div>
        <button onClick={ () => setCountOne(countOne + 1)}>+1</button>
        <button onClick={ () => setCountTwo(countTwo + 1)}>+1</button>
        { otherCount().value }
    </div>
}

useRef

useRef 會返回一個可以改變的 ref 物件,這個物件的 current 屬性會被初始化為傳遞的參數。使用方式很簡單,下面的範例中,我們調用 useRef 並賦給 inputRef 一個初始值,接著給 input 一個 ref 屬性,並將 inputRef 賦給 ref,之後就可以透過 geInput 獲取 inputRef 中的值

const UserProfile = () => {
    const inputRef = useRef(null)
    const geInput = () => {
        console.log(inputRef.current.value)
    }

    return <div>
        <input ref={ inputRef } />
        <button onClick={ geInput }>get input value</button>
    </div>
}

useImperativeHandle

useImperativeHandleuseRef 的拓展語法,它能讓我們把自定義的 ref 暴露給父元件。它接受兩個參數,第一個是 ref,第二個是函式,函式會返回一個物件給父元件

function Input(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
Input = forwardRef(FancyInput);

useLayoutEffect

useLayoutEffectuseEffect 基本一樣,但不同之處是 useLayoutEffect 會在所有 DOM 更新之後同步觸發,可以使用它來讀取 DOM 布局並同步觸發重新渲染。一般情況下,應該盡量使用 useEffect,以免阻塞視覺的更新。useLayoutEffect 一樣是接受兩個參數,一個是函式,用來處理一些邏輯,一個是陣列,用來控制 useLayoutEffect 的執行。useLayoutEffect 因為用到的機會比較少,這邊就不多述,想了解更多可以閱讀 關於 useLayoutEffect,你需要知道的事 這篇文章。

useLayoutEffect(() => {
    const rootElement = document.getElementById('root')
    console.log(rootElement)
}, [])

上一篇
【Day 26】React Hook(三): useReducer
下一篇
【Day 28】React Hook(五): 自定義 Hook 及 使用 Hook 的一些規則
系列文
React 30 天學習歷程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言