# React Hook - useCallback
###### tags: `Javascript, React`
> 1. 使用起來跟 useMemo 非常像,一樣是可以確保 referencial equality ,確保返回的函式不會因為任意的畫面 re-render 而被重新創造出來
> 2. 第二個比較常用到的地方則是當創造一個 function 時非常非常慢時
> 3. 與 useMemo 最大的差異是 useCallback 返回其函式本身 / useMemo 返回其函式的值
# 範例說明
這次的 DEMO 主要會操作這個 input form 主要改變數字的時候下方的 list 也會同時顯示並且顯示 本身, +1 , +2
並且可以更改 backgroundColor 藉由按鈕 toggle theme 達成

## App.js
```javascript=
import './App.css';
import React,{useState} from 'react';
import List from './List';
export default function App() {
const [number, setNumber] = useState(1);
const [dark, setDark] = useState(false);
const getItems = () => {
return [number, number + 1, number + 2];
}
const theme = {
backgroundColor:dark? '#333':'#FFF',
color:dark? '#FFF': '#333',
marginLeft:'3rem',
marginTop:'3rem'
}
return (
<div style={theme}>
<input type="number" value={number} onChange={e => setNumber(parseInt(e.target.value))} />
<button onClick={() => setDark(prevDark => ! prevDark)}>Toggle theme</button>
<List getItems ={getItems}></List>
</div>
);
}
```
## List.js
```javascript=
import React,{useState,useEffect} from 'react'
export default function List({getItems}) {
const [items, setItems] = useState([])
useEffect(() => {
setItems(getItems())
console.log('Updating Items');
}, [getItems])
return items.map(item => <div key={item}>{item}</div>)
}
```
在 List.js 內有使用 useEffect 來操作當 getItems 更新了就會印出字樣 Updating Items

可是問題來了,當我使用 toggle theme 按鈕時他卻也觸發了

然而會發生這種情況是因為畫面的 re-render (更新 state dark )的時候 getItems function 都會被重新創造出來,所以儘管裡面的數字相同,但是 function 是新的所以 useEffect 會再把字樣 log 出來一次
在這種情況下就可以使用 useCallback (這邊的使用情境跟 useMemo 很像),因為它可以監聽變數,只有在變數改變的情況下才會重新創造 getItems function
```javascript=
const getItems = useCallback(() => {
return [number, number + 1, number + 2];
},[number])
```
所以當使用完畢後,我們 toggle theme 就算 re-render 畫面,也不會在觸發創造新的 getItems function 因為它已經使用 useCallback 監聽變數 number 了
## useCallback 以及 useMemo 最大的區別
> useMemo: Returns and stores the calculated value of a function in a variable
> useCallBack: Returns and stores the actual function itself in a variable
useMemo 會返回指派給變數的函式的值
useCallback 則是會返回指派給變數的函式的本身
所以你可以這樣操作 useCallback
```javascript=
const getItems = useCallback((incrementor) => {
return [number+ incrementor, number + 1+incrementor, number + 2+incrementor];
},[number])
```
因為返回的是函式本身所以是可以代入參數進去使用的
```javascript=
import React,{useState,useEffect} from 'react'
export default function List({getItems}) {
const [items, setItems] = useState([])
useEffect(() => {
setItems(getItems(50))
console.log('Updating Items');
}, [getItems])
return items.map(item => <div key={item}>{item}</div>)
}
```
呈現結果如下

所以同樣的你會使用到 useCallback 最主要的情況也是在你要注意 referencial equality 的時候,因為每次 re-render 的時候都會創造新的 function 因此需要使用到 useCallback 來確保只有在監聽的變數更新時,才會更新 function
以這邊的例子來說明的話就是,確保了只要不是 number 更新的情況下, getItems 的 funtion 是不會被改變的因此可以確保它的 referencial equality
## 第二種使用情景就是當創造一個 function 時非常非常慢
如下方的範例可以看出,要執行這個 slowFunction 顯然需要非常多的時間,所以我們不能在每次 re-render 畫面的時候都觸發重新創造這個函式,因此使用 useCallback 來確保只有當 number 更新時才會觸發重新創造這個 function 增進其效能
```javascript=
function slowFunction(num){
console.log('call slow function');
for(let i=0; i<1000000000; i++ ){}
return num*2;
}
const doubleNumber = useCallback(()=>{
returm slowFunction(number
)},[number])
```