useMmo
是用來優化性能的,他利用函式的回傳值來判斷元件是否需要重新渲染,可以用在比較複雜的邏輯處理上。它接受兩個參數,第一個是 callback
,用來處理計算邏輯,第二個是 array
,當 array
發生改變,useMemo
才會重新執行。useMemo
會有一個記憶值,這個記憶值就是 callback
的返回值,當 array
發生改變,才重新計算記憶值。
const memoizedValue = useMemo(callback, array)
下面是一個簡易的範例,我們在 TestComponent
中設了兩個屬性 countOne
、countTwo
,每次點擊 button
就會分別更新這兩個屬性,而 otherCount
應該要在 countOne
有變動時才跟著變動。但是實際運作中會發現,因為 React 的特性,只要每次 countOne
或 countTwo
更新,整個元件就會一起更新,所以 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
和 useMemo
一樣是用於性能優化,一樣是有 callback
和 array
兩個參數,callback
也是處理計算邏輯,array
發生改變時,useCallback
才會執行。useCallback
的返回值也會記憶緩存起來,跟 useMemo
的差異處在於,useMemo
的返回值就是 callback
返回值,useCallback
的返回值是 callback
函式本身。
const memoizedCallback = useCallback(callback, array)
下面是一個和 useMemo
一樣的範例,但不同的是,我們用 useCallback
返回得到的函式。useCallback
和 useMemo
的使用時機,取決於產品的業務邏輯。
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
會返回一個可以改變的 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
是 useRef
的拓展語法,它能讓我們把自定義的 ref
暴露給父元件。它接受兩個參數,第一個是 ref
,第二個是函式,函式會返回一個物件給父元件
function Input(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
Input = forwardRef(FancyInput);
useLayoutEffect
和 useEffect
基本一樣,但不同之處是 useLayoutEffect
會在所有 DOM
更新之後同步觸發,可以使用它來讀取 DOM
布局並同步觸發重新渲染。一般情況下,應該盡量使用 useEffect
,以免阻塞視覺的更新。useLayoutEffect
一樣是接受兩個參數,一個是函式,用來處理一些邏輯,一個是陣列,用來控制 useLayoutEffect
的執行。useLayoutEffect
因為用到的機會比較少,這邊就不多述,想了解更多可以閱讀 關於 useLayoutEffect,你需要知道的事 這篇文章。
useLayoutEffect(() => {
const rootElement = document.getElementById('root')
console.log(rootElement)
}, [])